Getting around the flicker of JavaScript modifying the DOM while the page is loading

When building things with progressive enhancement, I often want the page styled a certain way when JavaScript is on vs off. When you use $(document).ready() in order to modify your page, you may end up watching the page modify before your very eyes, and if you’re like me, wish you could find a way around it.

For instance, I might have portions of a form hidden by default unless the user clicks an option to expand it. My old method was to show it all by default, then using $(document).ready(), hide those options. The problem is that I would see a flicker as elements start appearing then disappearing on my screen.

Now I use this method:

<body class="nojs">
      var bodyEl = document.getElementsByTagName('body');
      bodyEl[0].className = bodyEl[0].className.split('nojs').join(' jsEnabled ');

So by default, my page has a nojs class. And a script runs immediately after to remove that class, and to add in a ‘jsEnabled’ class in its place. I can then do things in my stylesheet like this:

.conditionalContent { display:none; } // what I really want to happen
.nojs .conditionalContent { display:block; } // in case JS is disabled

This accomplishes the same thing as I was trying to do above (keep an element hidden by default if JavaScript is disabled, but show it by default if JavaScript is disabled) but without the flicker.

And then you also have an option to make use of .jsEnabled class in the stylesheet as well.

If you happen to have jQuery pulled into your site in your <head>, you can use this instead:

<body class="nojs">

If anyone’s discovered other methods of getting around this type of issue (like using Modernizr, or something else), I’d love to hear about it.

3 thoughts on “Getting around the flicker of JavaScript modifying the DOM while the page is loading

  1. This is a really useful technique and is something I use on every site I develop. I have a slightly different syntax, which adds the .js class to the html element instead of the body. I also include this before I link to any CSS. Although this might not be allowed by the spec, it’s something that is completely supported. The syntax I use is below:

    document.getElementsByTagName('html')[0].className += ' js';

    You mention Modernizr, which does exactly the same thing as you and I describe — it adds a .js class to the html (it also adds a plethora of other class names for you to hook on to). You include Modernizr in the head, someone gave me the following updated syntax, which only adds the .js class if Modernizr hasn’t already:

    if (typeof Modernizr === 'undefined') {
    var docElement = document.documentElement;
    docElement.className = docElement.className.replace(/(^|\s)no-js(\s|$)/, ' js ');

    The only thing I would question with regards to your solution, is the methodology of your CSS, instead of styling the .nojs, I assume everything non-prefixed is with and without JavaScript, then I prefix the JavaScript-enabled styles with the new class.

    .conditionalContent { display:block; } // default state
    html.js .conditionalContent { display:none; } // when JS is enabled

    For me, this makes more sense. Firstly I think it follows the progressive enhancement idea (which I’m sure you’re doing) more closely). Secondly, it continues to work correctly if you don’t add the .no-js class / JavaScript added class, which means you follow best practice of making sure everything works without JavaScript first, before enhancing the project with JavaScript.

    Let me know your thoughts.

  2. Works great, thanks! Kicks in before Modernizr and solves any lingering flickering on elements that are hidden when enhanced.

Comments are closed.