How do I stop the flash of unstyled content (FOUC) on a web page?
-
This happens many a times if we have the link tag of style sheets referred at the bottom of the web page. – RBT Jun 18 '16 at 23:47
-
@RBT can you explain a bit more? – Evaa Oct 30 '22 at 12:56
14 Answers
The problem with using a css style to initially hide some page elements, and then using javascript to change the style back to visible after page load, is that people who don't have javascript enabled will never get to see those elements. So it's a solution which does not degrade gracefully.
A better way therefore, is to use javascript to both initially hide as well as redisplay those elements after page load. Using jQuery, we might be tempted to do something like this:
$(document).ready(function() {
$('body').hide();
$(window).on('load', function() {
$('body').show();
});
});
However, if your page is very big with a lot of elements, then this code won't be applied soon enough (the document body won't be ready soon enough) and you might still see a FOUC. However, there is one element that we CAN hide as soon as script is encountered in the head, even before the document is ready: the HTML tag. So we could do something like this:
<html>
<head>
<!-- Other stuff like title and meta tags go here -->
<style type="text/css">
.hidden {display:none;}
</style>
<script type="text/javascript" src="/scripts/jquery.js"></script>
<script type="text/javascript">
$('html').addClass('hidden');
$(document).ready(function() { // EDIT: From Adam Zerner's comment below: Rather use load: $(window).on('load', function () {...});
$('html').show(); // EDIT: Can also use $('html').removeClass('hidden');
});
</script>
</head>
<body>
<!-- Body Content -->
</body>
</html>
Note that the jQuery addClass() method is called *outside* of the .ready() (or better, .on('load')) method.

- 3,850
- 2
- 26
- 39
-
4To me it seems cleaner to replace `$('html').show()'` with `$('html').removeClass('hidden');`. This makes it clearer that the ready function is undoing the `addClass`. – ToolmakerSteve Aug 12 '14 at 02:22
-
7UPDATE: Just tested this approach. The current version of jQuery REQUIRES this to be done using `removeClass` (as I suggest) rather than `show` (as in the original answer) -- otherwise the html will NEVER show. I believe jQuery's show() now explicitly looks for and restores any display state from css styling, to avoid interfering with styling. Therefore, it is necessary to actually remove the 'hidden' class. – ToolmakerSteve Aug 12 '14 at 02:40
-
@ToolmakerSteve: The only reason I used both `addClass('hidden')` and then `show()` instead of `removeClass()` was just to demonstrate that there is more than one way to show and hide the html. I will also test to confirm if `show()` can still be used or not with recent jQuery - I believe it did work at the time when this was posted. – Stefan Aug 12 '14 at 05:39
-
@ToolmakerSteve: I retested using `//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js` and found that using `show()` as above still works...? As you say, `http://api.jquery.com/show/` states that the display state is restored to whatever it was initially, however even though not explicitly stated, this (almost obviously) can't be true if the initial state was `hidden`, in my view. (Caveat: `show()` will not work if `jQuery.fx.off = true;`) – Stefan Aug 12 '14 at 06:34
-
1Works perfectly. Opted for the removeClass option rather than show() – FurryWombat Feb 21 '15 at 20:12
-
4What about a CSS only solution where you have `` in the ``, and then your real styles right before ``? – Adam Zerner May 05 '17 at 20:21
-
2Shouldn't we be looking for the load event instead of ready? With load, we know the CSS will be ready. With ready, we don't know the CSS will be ready. – Adam Zerner May 05 '17 at 20:24
-
1@Adam Zerner: Re css only solution: I think that is quite brilliant. It is now possible in HTML5 to use `link` (with `itemprop` insead of `rel` attribute) and/or `style` (with `scoped` attribute) tags inside `body` tags without violating standards. Re `load` versus `ready` event: I think you are correct, it would be better to use `load`, since css and images are then also guaranteed to be loaded. Why don't you add these insights as an additional answer to this thread? – Stefan May 06 '17 at 09:52
-
1@Stefan, thanks for the input :) I didn't add it as an additional answer because I figured I may have been wrong, but I'll go ahead and do so now. – Adam Zerner May 06 '17 at 17:07
-
Great. I see `itemprop` is no longer mentioned as required, in the latest specs for the `link` element: http://w3c.github.io/html/document-metadata.html#the-link-element – Stefan May 06 '17 at 21:09
-
So, if JS is disabled by the user, I assume we can't avoid FOUC for him/her using this method? – Kevin Apr 09 '18 at 03:27
-
1@Kevin 2 Yes that is correct. Adam Zerner's method does not suffer from this requirement. Although, who in this day and age still has javascript disabled...? – Stefan Apr 09 '18 at 06:12
-
-
1@Kevin 2 The only real downside I can see, is what Adam mentions at the end of his post: You have to place the link tag at the bottom of the document, which is not the expected placement, although it is allowed by more recent HTML standards. Then, you must remember to deliberately display the html element, in the externally referenced stylesheet. However in my opinion, Adam's method is better: It is simpler, and will also work for the 0.2% of users who disable javascript. – Stefan Apr 09 '18 at 08:56
This is the one that has worked for me and does not require javascript and it works great for pages with many elements and lots of css:
First, add a dedicated <STYLE>
setting for the <HTML>
tag with visibility 'hidden' and opacity as '0' at the top of your HTML, e.g, in the beginning of the <HEAD>
element, for example, at the top of your HTML add:
<!doctype html>
<html>
<head>
<style>html{visibility: hidden;opacity:0;}</style>
Then, at the end of your last .css stylesheet file, set the visibility and opacity styles to 'visible' and '1', respectively:
html {
visibility: visible;
opacity: 1;
}
If you already have an existing style block for the 'html' tag, then move the entire 'html' style to the end of the last .css file and add the 'visibility' and 'opacity' tags as described above.
https://gist.github.com/electrotype/7960ddcc44bc4aea07a35603d1c41cb0

- 1,362
- 14
- 17
-
9This one really should be the accepted correct answer. Not showing any page if JS is disabled or if there is a JS error is a bad idea and this is much more accessible. – braindigitalis Dec 03 '18 at 11:52
-
-
1This also doesn't interfere with browsers that have CSS disabled (e.g. those with low-speed Internet access or have disabilities might opt to disable images, Javascript, and CSS). Opera was probably the most famous example of a browser that had, at one point, a button on the main toolbar to turn off CSS. The downside to this approach is if the CSS file fails to load, the page will be blank. For example, naming your CSS file "ads.css" will trigger ad blocker plugins and the file will fail to load, thus leaving the page completely blank. (Of course, that could be intentional...) – CubicleSoft Aug 15 '19 at 01:43
-
This is the technique which I employ and like best; however, I find that I need to use `html{display:none;}` in the `head` and `html{display:block;}` in the stylesheet to fully conquer FOUC with Chromium-based browsers. (I haven't experienced problems with a dark background set on the `body`.) – dotism Sep 04 '19 at 13:00
-
1There is virtually no difference between this solution and Adam Zerner's solution, more than a year ago. – Stefan Sep 08 '19 at 16:49
-
Thank you Jeff. This solution works. Don't forget to add `!important` to the css you add at the bottom of the stylesheet. – nflauria Sep 09 '19 at 03:30
-
1This also works if you add another style tag at the end of your body with ``. No need to modify your css files if you don't want to. See: https://gist.github.com/mig8447/dc669de679fc55623032ed70d8697012 – Miguel Sánchez Villafán Nov 11 '20 at 00:19
-
A variation of this I used was to set the background colour in the top inline style and hid the content, so at least the colour was not white before the content showed up. However, it produced pronounced delays. I now use totally inline styles in the head. I pre-process the css with embedded php to eliminate css for content that doesn't exist on the given page, among other optimisations, then eval() it, get its hash, and insert the css into the html with the hash in the CSP header. I do the same with the fairly sparse js as well. No flash, minimal css, and best security practice. – Patanjali Sep 24 '21 at 05:08
-
Could this technique be potentially bad for page speed? E.g. for speed score at https://pagespeed.web.dev/ – datasn.io May 10 '22 at 05:43
-
-
This is the correct answer BUT all the resources you want to be loaded have to be inlined into the css, such as @font-face { font-family: "Foo", src: url('data:application/x-font-ttf;charset=utf-8;base64,AAEAAAALAIAAAw... – Gregory Magarshak Nov 20 '22 at 22:46
A CSS-only solution:
<html>
<head>
<style>
html {
display: none;
}
</style>
...
</head>
<body>
...
<link rel="stylesheet" href="app.css"> <!-- should set html { display: block; } -->
</body>
</html>
As the browser parses through the HTML file:
- The first thing it will do is hide
<html>
. - The last thing it will do is load the styles, and then display all the content with styling applied.
The advantage to this over a solution that uses JavaScript is that it will work for users even if they have JavaScript disabled.
Note: you are allowed to put <link>
inside of <body>
. I do see it as a downside though, because it violates common practice. It would be nice if there was a defer
attribute for <link>
like there is for <script>
, because that would allow us to put it in the <head>
and still accomplish our goal.

- 1
- 1

- 17,797
- 15
- 90
- 156
-
8Useful to know that `display: none` will also hide the background image or color. Since my website has a dark theme, it would flash white. Using `visibility: hidden` was better for my case. – KamilDev Sep 18 '18 at 02:50
-
1This solution will work even if the reference to the stylesheet is in the `` instead of ``. (Although I suppose if you had a really long page, the browser might start display the page before the end of the page had been loaded. However, that is actually my preferred behavior since my site is loading large tables from a database). Thumbs up for a simple solution that doesn't require JavaScript! – Matt Nov 28 '18 at 16:03
-
-
@Richard this can work, but you need to inline your fonts into the CSS files, for example @ font-face { font-family: 'ITR-icons'; src: url('data:application/x-font-ttf;charset=utf-8;base64,AAEAAAALAIAAAwAwT1MvMg8SB/ ... – Gregory Magarshak Nov 20 '22 at 22:47
A solution which doesn't depend on jQuery, which will work on all current browsers and do nothing on old browsers, include the following in your head tag:
<head>
...
<style type="text/css">
.fouc-fix { display:none; }
</style>
<script type="text/javascript">
try {
var elm=document.getElementsByTagName("html")[0];
var old=elm.class || "";
elm.class=old+" fouc-fix";
document.addEventListener("DOMContentLoaded",function(event) {
elm.class=old;
});
}
catch(thr) {
}
</script>
</head>
Thanks to @justastudent, I tried just setting elm.style.display="none";
and it appears to work as desired, at least in current Firefox Quantum. So here is a more compact solution, being, so far, the simplest thing I've found that works.
<script type="text/javascript">
var elm=document.getElementsByTagName("html")[0];
elm.style.display="none";
document.addEventListener("DOMContentLoaded",function(event) { elm.style.display="block"; });
</script>

- 63,018
- 25
- 139
- 189
-
the mentioned code did not work for me, here's my version: try{ var html=document.getElementsByTagName("html")[0]; document.addEventListener("DOMContentLoaded", function(event) {html.className=''; }); html.className='fouc'; } catch(err) {} – Manfred Wuits May 24 '16 at 08:04
-
I like this approach, but would like to suggest the usage of the [`classList`](https://developer.mozilla.org/en-US/docs/Web/API/Element/classList) API. – Just a student Sep 15 '17 at 11:00
-
2In fact, why use the separate CSS in the first place? Why not do `elm.style.display = 'none';` and then undoing that with `elm.style.removeProperty('display');`? – Just a student Sep 15 '17 at 11:15
-
@Justastudent : Because that would display a blank page in the event that Javascript is disabled. – Lawrence Dol Sep 15 '17 at 18:54
-
@Justastudent : RE `classList` API. Sure, but this kind of thing you need to be as backward-compatible as possible; `classList` is only IE 10+. Of course, that was more relevant 2 years ago, than today, but it still matters. – Lawrence Dol Sep 15 '17 at 18:56
-
@Lawrence No, it wouldn't. The code hiding the HTML would not execute either. – Just a student Sep 15 '17 at 18:57
-
@Justastudent : Of course, I was mentally thinking of something else. I have a vague recollection of trying that, but can't remember for sure. Perhaps you can't display=none for the HTML element. – Lawrence Dol Sep 15 '17 at 18:59
-
1@Justastudent: Thanks. I tried that, and it works, at least in current browsers. Answer augmented. – Lawrence Dol Oct 02 '17 at 21:21
An other quick fix which also works in Firefox Quantum is an empty <script>
tag in the <head>
. This however, penalizes your pagespeed insights and overall load time.
I had 100% success with it. I think it's also the main reason, why above solutions with other JS in the works.
<script type="text/javascript">
</script>

- 4,109
- 1
- 24
- 48

- 186
- 2
- 14
None of the CSS-only solutions presented here work with modern browsers (asynchronous loading of css and fonts). You have to use Javascript. What I've done to avoid FOUC is:
<html>
<body onload="document.body.style.visibility=`visible`;">
<script>document.body.style.visibility=`hidden`;</script>
With this approach the body of my web page is kept hidden until the full page and CSS files are loaded. Once everything is loaded, the onload event turns the body visible. So, the web browser remains empty until a point when everything pops up on the screen.
It is a simple solution but so far it is working.
This will not affect users who have disabled Javascript because the <script>
tag is ignored.

- 14,798
- 21
- 70
- 103

- 354
- 2
- 3
-
69Not good if a viewer does not have javascript enabled, because then they won't see a thing. – Stefan Mar 29 '12 at 14:29
-
23-1 for suggesting a solution that will show NOTHING for users who don't have javascript enabled, or are on a screen reader that doesn't support javascript, or who are behind a corporate firewall that blocks javascript. Googling "eliminate flash of unwanted content" will show numerous approaches that don't have this flaw. For example, Stefan's answer (a year later) is much safer. – ToolmakerSteve Aug 12 '14 at 02:06
-
23You really should add `` at the end so that the site will work with JS disabled too. – tomasz86 May 16 '16 at 01:51
-
10Corporate firewalls blocking Javascript? A reason to change the company... – unwichtich Nov 07 '18 at 16:07
-
4The answer below from Jeff is the correct answer in my opinion. It doesn't rely on javascript and is more accessible. – braindigitalis Dec 03 '18 at 11:53
-
1I added a solution that doesn't require making anything invisible/visible. It addressed the reason why I was suddenly getting the FOUC error. The root cause of my issue was that I was importing my CSS after I imported some javascript, and this caused a slight slowdown in styling being applied. So by moving my CSS imports to the top of , it allowed vital styling to be imported earlier, resulting in everything displaying correctly. Give it a look over, it might help you. Also, downvoted Accepted Answer for same reasons as @ToolmakerSteve & bc it relies on assumption that the FOUC is normal – Jake Boomgaarden Feb 08 '19 at 15:07
-
1
-
1
-
Everyone is saying that JS-disabled browsers will show nothing. No. If JS is disabled, visibility is never set to "hidden". – José Ramírez Aug 18 '23 at 04:41
No one has talked about CSS @import
That was the problem for me i was loading two extra style sheets directly in my css file with @import
Simple solution: Replace all @import
links with <link />

- 9,298
- 2
- 35
- 55
-
This happened to me. I hope in the future `@import` will be synchronous. – D. Pardal Jun 27 '19 at 10:26
-
That's not true, `@import` is not asynchronous, they're effectively equivalent to `link` tags, even when nested. However they should still [avoided](https://discourse.wicg.io/t/is-css-import-still-considered-as-an-anti-pattern/1967) so the suggestion is still good. – fregante Oct 19 '22 at 05:42
Every answer on this page slows down the load and it only hides the underlying issue. If you're experiencing FOUC, find out WHY it's happening and fix that.
At the core, this is happening:
- because your stylesheets are not being loaded correctly: they should be loaded via
link
tag in the HTML, not via JavaScript - because you placed
script
tags beforelink
tags, which may force a "layout operation" and trick the browser into rendering before it even attempts to load the style.
For reference, here's an example of FOUC:

- 29,050
- 14
- 119
- 159
I came up with a way that requires no real code change whatsoever, woohoo! My issue was related to importing several css files AFTER some javascript files.
To resolve the issue I just moved my CSS links so that they would be above my javascript imports. This allowed all my CSS to be imported and ready to go ASAP, so that when the HTML appears on the screen, even if the JS isn't ready, the page will be properly formatted

- 3,394
- 1
- 17
- 31
Here is my code .. hope it solve your problem
set <body style="opacity:0;">
<script>
$(document).ready(function() {
$("body").css('opacity', 1);
});
</script>

- 39
- 2
-
Amazingly, amongst dozens of snippets that don't work to stop FOUC - this one actually works - for me. Note there is a missing end " on the body style, should be `` – abulka Oct 17 '19 at 01:49
A simple solution to avoid a flash of unstyled content without javascript:
<!DOCTYPE html>
<html>
<head>
<title>Bla bla</title>
<link href="..." rel="stylesheet" />
<link href="..." rel="stylesheet" />
</head>
<body style="opacity: 0">
<!-- All HTML content here -->
<script src="..."></script>
<script src="..."></script>
<style>
body {
opacity: 1 !important;
}
</style>
</body>
</html>
When the parser arrives at the body, it is faded out using "opacity: 0". When the parser finally arrives at the very bottom after everything else is parsed, the body is faded in again using an in-page style. The !important keyword there is important ;-), because it overrules the previous inline style of the body tag.
In this case, using "opacity: 0" to fade out is better than "display: none", because if you have layout operations done by javascript, they may not work when the affected element is not rendered.
That worked for me.

- 862
- 8
- 4
-
Nice and easy. Cheers. Can add a fade in transition to sweeten it up `transition: all 1000ms ease-in;` – Reggie Pinkham Aug 12 '22 at 23:30
The best solution I found till now is like this:
Add all styles of your header to a
<style/>
tag in<head/>
at the top of style tag add
.not-visible-first{visibility: hidden}
+ other header styleAdd css via JS at the end of body
document.getElementsByTagName("head")[0].insertAdjacentHTML("beforeend","<link rel=\"stylesheet\" href=\"/css/main.min.css?v=1.2.4338\" />");
And remember to add
.not-visible-first{visibility: visible}
to the end ofmain.min.css
This option will create better user experience

- 4,218
- 1
- 35
- 43
You could try this with vanilla
function js_method(){
//todos
var elementDiv = document.getElementById("main");
elementDiv.style.display ="block";
}
<body onload="js_method()" id="main" style="display:none">
//todos
<h2>Hello</h2>
</body>

- 478
- 1
- 10
- 19
For me, fixing FOUC on FireFox was easy as changing the css linking code in my <head>
from this:
<link rel="stylesheet" href="/assets/main.css">
...To this:
<link rel="stylesheet" type="text/css" href="/assets/main.css" />
I believe including the type="text/css"
helps FireFox prioritize CSS loading and rendering? That's my take. Cheers!