How do I stop the flash of unstyled content (FOUC) on a web page?
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>
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.
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>
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>
What I've done to avoid FOUC is:
Set the body section as: <body style="visibility: hidden;" onload="js_Load()">
Write a js_Load()
JavaScript function: document.body.style.visibility='visible';
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.
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:
<html>
.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.