The Most Effective Way to Avoid the FOUC

This post was previously updated on November 01, 2018.

We all have to deal with it at some point.

The Flash Of Unstyled Content. Yuck. What a name. According to TechRepublic it has its origins documented as far back as 2001. There are a wide range of fixes. This fix however is super duper easy to implement and it’s a vanilla solution.

First, add a class to your html document

<html class="no-js">...

Then put this little guy at the very-bottom of your scripts file:

(function(H){H.className=H.className.replace(/\bno-js\b/,'js')})(document.documentElement)

And finally add this to your CSS, render content invisible until it loads:

visibility: hidden;
 opacity: 0;
}

.js {
 visibility: visible;
 opacity: 1;
}

The obvious downside to this is pretty awful. If a user comes along that doesn’t have JS enabled, your page loads but it isn’t visible. It really comes down to a pros and cons list for your users. If you’re Facebook or Google, you probably have this baked into every single product because every single product uses JS in some small or large way.

I’m not saying this is the best solution ever — I’m just saying it’s the most effective solution we have right now. This method is a Frankenstein version of Paul Irish’s approach. Which if you’re going to use this FOUC solution you better be using Irish’s DOM Based JS Routing. Then you can really iron down when and where you want JS to fire.

UPDATE: Thanks to Bert, who reminded me that I haven’t written about FOUC solutions in some time, and happy to revisit the subject.

I do have a newly updated solution. It’s not much different than above but it’s more performant.

We continue to re-use Paul Irish’s famous markup from 2009, with only marginal updates. Such as, the no-js class on the document, and script in the <head> (not in the body, nor in the footer, this needs to be parsed right-away):

<html class="no-js">
<head>
  <script>(function(H){H.className=H.className.replace(/\bno-js\b/,'js')})(document.documentElement)</script>
...

Next, we write CSS for the no-js state:

.no-js {
 visibility: hidden;
 opacity: 0;
}

.js {
 visibility: visible;
 opacity: 1;
}

And Bob’s your uncle! Same as before, but only slightly revised for performance. Enjoy!

UPDATE: There’s more than one way to skin a cat as they say. Many thanks to elektrotype, who came up with this brilliant solution, which works great for no-js users. In-short, they won’t see a white-screen if they don’t have JS enabled:


Subscribe to the blog

Join my email list and receive dispatches from the blog automatically. New subscribers receive a FREE $50 hosting credit at DigitalOcean.

10 Comments

Add Yours →

I read your article on avoiding FOUC. It seems a dangerous practice, to initially hide page content via CSS to everyone. As you point out, if JS is not enabled, nothing is displayed on the page.

So why not have the ‘visibility: hidden’ class of CSS assigned via vanilla JS in the head? Surely that way, if a page is loaded without JS enabled the ‘visibility: hidden’ class of CSS is never assigned and the page is loaded with some form of content.

I would really like to hear your opinion on this alternative approach and if that seems safer.

Kind regards,
Chris.

I think you’re totally onto something here!

Instead of assigning the no-js class to html we setup the document with no class out-of-the-box and a stylesheet like this:

  .loading {
    visibility: hidden;
    opacity: 0;
  }

  .js {
    visibility: visible;
    opacity: 1;
    transition: 5s ease;
  }

Then we can assign the DOM a loading class with JS:

 var root = document.documentElement;
 root.className += 'loading';
 (function(H){H.className=H.className.replace(/\bloading\b/,'js')})(document.documentElement)

Thoughts on this method?

Hi Stephen, I just came across this possible solution for the FOUC. I’m wondering if there has been any further development? I’m wanting to give this a try but want to know if you’ve tinkered any further.

Displaying a white page when javascript is disable is really an idea I dislike (a lot).

Here’s what work for me, no javascript required. I don’t know how this blog will parse HTML in comments so here’s a Gist.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.