1 Way To Avoid the Flash of Unstyled Content
read 77 commentsThis tutorial describes a way to avoid a flash of unstyled content that sometimes occurs when applying styles with JavaScript on page load. The problem is most evident when there is some content that needs to be hidden initially and when the document is large or complex. We can see an example of the problem on this test page.
The page is a copy of a previous entry on this blog with over 140 comments—quite a lot of content. Look for the bright yellow background before the page finishes loading. That's the part that is supposed to be hidden from the start — a simple unordered list, <ul id="flash">.
In pages with a more reasonable length, the standard jQuery code would work just fine:
But in this page there is a whole lot of document that has to be ready before anything inside the $(document).ready() function can be executed. Too much, in fact. And putting the <script> tags just inside the closing </body> tag doesn't help either. No, using JavaScript to hide elements like this just won't work unless the scripts are placed in the HTML immediately following the elements they're hiding.
Why Use JavaScript for This, Anyway?
Before we examine how to fix the problem, we might need to answer the question, Why bother? I mean, isn't that what CSS is for? Certainly we could add a rule to our stylesheet, such as #flash {display: none;}, and our problem would be solved.
But the pure CSS solution introduces another problem: the hidden content is completely unavailable to those who have CSS enabled/available but JavaScript disabled/unavailable. These users simply won't be able to view the content. Now, some developers don't have a problem with that, but as a proponent of Progressive Enhancement™, I believe that a user should be able to see content at the very least when visiting a web page (okay, okay, full-scale RIAs could be an exception).
A Simple Solution
Rather than attempt a pure CSS solution or a pure JavaScript solution, why not try a hybrid of the two? Here is how it might look (Important: I'm embedding styles and scripts here for the purpose of demonstration, but linking to separate files instead is recommended):
- <html>
- <head>
- <!-- etc. -->
- <style type="text/css">
- .js #flash {display: none;}
- </style>
- <script type="text/javascript" src="/scripts/jquery.js"></script>
- <script type="text/javascript">
- $('html').addClass('js');
- $(document).ready(function() {
- // Stuff to do as soon as the DOM is ready
- });
- </script>
- </head>
- <body>
- <!-- etc. -->
- </body>
- </html>
The first thing to note here is that the CSS is hiding an element with id="flash" only if it is a descendent of an element with class="js". Now, which element can we add a class of "js" to immediately, from within the <head>, and have it be applied before the slightest bit of the body is visible? Why, the <html> element, of course!
Line 9 shows the "js" class being added. And since it's being added with JavaScript, only those users who have JavaScript enabled will have their <ul id="flash"> initially hidden. Take a look at the beautiful invisibility demonstrated here.
Significantly, the .addClass() method is not inside $(document).ready(). If we had put it inside, we'd be back to square one.
If you follow the YUI advice to put scripts at the bottom, we can still make this solution work for you. We just use ye plain olde JavaScript for our one-liner to add the "js" class, keep that one in the <head>, and dump the other scripts down below, like so:
- <html>
- <head>
- <!-- etc. -->
- <style type="text/css">
- .js #flash {display: none;}
- </style>
- <script type="text/javascript">
- document.documentElement.className = 'js';
- </script>
- </head>
- <body>
- <!-- etc. -->
- <script type="text/javascript" src="/scripts/jquery.js"></script>
- <script type="text/javascript">
- // Stuff to do as soon as the body finishes loading.
- // No need for $(document).ready() here.
- </script>
- </body>
- </html>
Thanks to Brandon Aaron for the tip to use document.documentElement rather than document.getElementsByTagName('html')[0]
This one, demonstrated here, hides <ul id="flash"> as completely and awesomely as the previous one. Simple!
















Hi Karl, I use a slightly different approach here: what is used with JavaScript only - add it with JavaScript. Thus I add a style sheet via document.write after all other style sheet references. You can neglect the
.jspart in the selectors in that case.document.write of course may have negative impact on page rendering time but as long as it's only a single one I felt it's ok.
(And for the purists: The HTML spec doesn't have a class attribute for the
htmlelement, so a theoretical super strict browser could ignore it. In practice all browsers seem to support it.)PS: Nice new design!
Hi!
Just a note: beware of relative links for your examples, because it is broken when users read your articles from feedburner or google reader.
Anyway thanks for the tip!
Klaus,
Thanks a lot for the comments. I'm glad you like the design!
The document.write trick is an interesting idea that, admittedly, I hadn't thought of yet. Sam Collet also mentioned it to me on Twitter today (great minds think alike, I suppose). Having come to JavaScript on the wave of the DOM scripting / Unobtrusive JavaScript revolution, I had in mind that document.write was somehow a poor practice. But, hey, if it works and there are no discernible side effects, why not?
You're right, of course, about the class attribute not being valid for the
htmlelement. I meant to note that in the entry, but forgot. Glad you brought it up. I figured that since it works and the class isn't hardcoded into the HTML, most people would be willing to overlook that.Thanks again, Klaus. It's always great to see how you tackle these issues.
manu, I appreciate the warning about relative links. I'll go and fix them up now — although I don't know if that will have any effect on feed readers this time around. Do they incorporate post updates? Either way, thanks for mentioning.
This is a great tip. I was so impress beyond even what you mentioned I posted a follow on my blog.
This applications for this go beyond just fixing the flashing problem.
I apologize if I've missed something in the example, but shouldn't instead be
document.getElementsByTagName('html')[0].className = 'js';?You want the
htmltag, right?JFSIII, No apology necessary. You're right. Ack! That's what I get for typing this up so late at night. Duly noted and fixed. Thanks!
I've also usually used document.write to spew necessary css rules into the head, but this is an interesting approach and in some way slightly more elegant. I might try it next time i run up against this problem.
@Karl: Do they incorporate post updates?
>> Yep :-)
I've been using the code below ever since I came across content "flashing" or rendering of the page without my jQuery modifications applied yet. I link to the js file from the head of my document.
if (document.getElementById) {document.write('
<style type="text/css" media="screen">
#element1, .element2 {display:none;}
</style>
');
}
will haven,
Yeah, just like Klaus mentioned in the first comment. :)
Another CSS method, that works in some cases, say you are loading slides in a div, and know the size required.
Specify the size of the Div and have it set to overflow:hidden.
IT seems to work, and should have an image present, without the fading in slides, etc.
A technique I've been happy with, until now anyways - thanks gang.
I've been using the noscript tag to achieve the same effect...
ex:
...
<style type="text/css">
#flash { display:none}
</style>
<noscript>
<style type="text/css">
#flash {display: block}
</style>
</noscript>
...
Also, doesn't IE7 (or some other browser) not allow for DOM manipulation until the DOM is fully loaded? (or does adding a class name not factor in as a DOM change?)
By the way, you don't have to necessarily document.write a
styletag. You can as well use alink.@jlee I like that solution, unfortunately the HTML spec doesn't allow style elements inside noscript. To me this is clearly an oversight. Thus it's allowed in HTML 5 under certain circumstances, but the Spec did quite confuse me here.
Why not
$('head').append('<style type="text/css">#fox {display:none}</style>')
outside ready()?
Ricardo,
I suppose that would be fine, too. It might get a little messy if you have multiple style rules you want to apply.
Thanks for the tip Karl, this is just what I needed for a website I've been working on!! :D
Keep up the good work!
I've been using a similar technique: avoiding flickering in jQuery.
If you put your JS includes at the bottom of the document you can use the
document.documentElementreference instead of looking for it usinggetElementsByTagName.Replace this:
document.getElementsByTagName('html')[0].className = 'js';With this:
document.documentElement.className = 'js';thanks for the tip, Brandon!
I'm actually using
.nojsrather than.jsin thehtmltag. So I'm going against the tide - I hard code.nojsand then remove the class at the earliest possible point.There is no difference techincally but in terms of time consideration I could concentrate on the majority of users first then bake in for those that don't have Javascript later.
Ca-Phun Ung, one difference is that the class attribute is not valid on the
htmlelement, so if you're concerned at all about your page validating, adding it with JavaScript would be better than removing it with JavaScript.@karl: Point taken - that never crossed my mind :)
And what about progressive enhancement?
It is explained in this ALA article
Markus,
I'm well aware of what progressive enhancement means. That's the whole point of this post. It allows you to initially hide certain elements for those with JavaScript enabled, and those without JavaScript still get to see the content.
I'm sorry, I didn' mean to question whether or not you are aware of progressive enhancement, my real intention was to point the whole article as a solution to the topic of this post, not to teach you what it is progressive enhancement.
Well, in the post, a guy named Scott Jehl, designer at Filament Group, talks about a technique to test the user's device capabilities and make the enhancement only if the user's device meets some requirements. I think his technique is an interesnting solution to avoid the flash of unstyled content, as the script only loads the "enhanced" stylesheet when the dom is ready.
I'm sorry, too, Markus. I shouldn't have been so defensive. I've read Scott's article and enjoyed it.
To avoid the purists who won't let you put a class on the <HTML> element, you could just put it on the <BODY> element. I use <BODY> class switching a lot; it's like instantly changing stylesheets without the headache of enabling/disabling each one.
Hi Daniel,
Yes, setting (and switching) a body class is a time-honored tradition. Unfortunately, though, it sort of negates the benefit that you get with setting a class on the html element, which is that you can do it with JavaScript before anything in the body is registered/loaded and thus avoid the flash of unstyled content.
Putting the <SCRIPT> right after the opening <BODY> would avoid the flash; the element is created as part of the DOM as soon as the opening tag is parsed.
That so Interesting KARL ,
YOU are so prepomnderant in DOM .
fantastic
Wow, great tip here, I'm definitely going to start using this more!
Thanks for the inspiration Karl! This article helped fix a FOUC problem we've had for a while now.
Searched a lot to find a solution to hide content fast enough and here we go. Brilliant solution. Thank you very much.
Fantastic, just what I was looking for. Many thanks!
Great, implemented this and even put a animated loading gif, which disappears once my componets have loaded. BUT this works perfect in IE7, but in Firefox3, it hides the content shows my animated gif, then for a split second i see the hidden content before it bounces into action.
Where it use to sit there for 3-4 seconds before bouncing into action.
Karl if you want to see this in action i can email you a website link, its in development didn't want to post it here
Hey Mark, email a link to my first name at learningjquery.com and I'll have a look.
one thing that could be a major problem with this technique is that it hides large portions of your HTML with display: none; from your stylesheet instead of with javascript.
In the past google has mentioned that this is a technique that is used for blackhat SEO purposes and your text either isn't indexed or your page rank suffers (can't remember which)...
The way I ended up getting the best of both worlds (thanks to a lot of the info above) was to use old fashioned DOM scripting technique to add the jsActive class to the HTML tag, then also use DOM scripting to add a style tag to the head of the document and feed it the divs I need to hide... This way you don't have display: none added with CSS...
// add class of .jsActive to pages when javascript is available
document.documentElement.className = 'jsActive';
// add a style tag to the head of the document and hide some stuff up front before the DOM is ready so there's no flash of content
var headTag = document.getElementsByTagName('head')[0];
script = document.createElement('style');
script.type = 'text/css';
script.innerHTML = '#JSInd, #home #ShortGrass, .Hide { display: none; }';
headTag.appendChild(script);
I'm pretty sure this would be enough for google to at least think you have good intentions... Maybe someone who knows more about the SEO angle can chime in, because you could also use javascript to hide key words, so maybe google is savvy to this as well?
brent
@
mimoYmima.com
That's interesting. I hadn't considered the SEO angle. Still, since the elements are only receiving the display:none; with JavaScript enabled, I'm not sure it makes a difference. Another way to handle it is to avoid using display:none altogether. You could set your .js descendant elements that you want hidden to have text-indent: -1000em; or position:relative; left: -1000em; instead.
hiding the text by positioning it off screen was my first idea, but it didn't work for me with .show() for some reason.
It's a good point that the display: none isn't used unless javascript is active. That might be enough to make it not matter that it's in the stylesheet... Has anyone done any tests using hidden content to see what's indexed and what isn't by chance?
if anyone wants to use the method above you'll need to change the part that adds the style tag to the document to this:
I'm not a veteran with DOM Scripting methods, but the other code wasn't working in Chrome, but changing the method from innerHTML to .createTextNode seems to fix the problem
great solution!
Been searching for hiding some dom elements before page loads.
Otherwise I'd have to forget about animation effects.
Good tip!!!
Ok, I am going nuts trying to get this to work. Does it matter if the #flash is buried inside other div's? It just doe snot want to co-operate. Using FF 3.5
shouldn't matter at all where that div is. does it not work for you in my example page? Or is it not working on your own page? If on your own, send me a URL and I'll take a look.
for the 2nd set of eyes!
works in your page no problem. I sent you an email with the login.
Karl, this is great. Forgive the noob question, but what actually goes in place of " // Stuff to do as soon as the DOM is ready" ? I can get it to hide but not reappear at my site. Thanks!
Hi Nathan,
Maybe a different example would help. Let's say you have a utility CSS class called "js-hide" that you want to add to all elements that should be hidden when the page loads. You could do that like so:
Then, you might have an element in your html like this (with two classes, "js-hide" and "something"):
You can show that div later on, based on some user input or some amount of elapsed time or whatever. For example, you could toggle its visibility in response to a user clicking on a button:
I hope that helps!
It does, thanks. Instead of a user clicking to make it visible, what's the command to make it visible as soon as the page is ready? To un-hide, in other words, when it's "safe" to show the content without it appearing un-styled?
If you want to wait until the page, along with all the images, has loaded, you could do something like this:
Dang, still not working. Here's a snippet of my JS in my header (at http://www.nbierma.com):
http://wordpress.pastebin.com/m3bc2d3f
and the HTML of the slideshow I'm trying to hide until it's ready:
http://wordpress.pastebin.com/m378e7f9a
(or view source, of course, at nbierma.com)
I think I'm going to need to see all of the html/css/javascript to troubleshoot this one. If it's not public yet, maybe you could send a link to my first name at learningjquery.com?
It is, so you can view source, but I'll also e-mail it. Thanks!
to add part of html, then it is possible so:
$('html').html();
$('#add_class_html').hide();
Thanks for this example, it solved a problem I'd been struggling with for a while. Very happy with the solution!
Brilliant. Thanks for posting.
µ
Hi Karl, let's say a page has a JavaScript statement in the HEAD that is used to add a class named "js" to the HTML element. This js class is used to write CSS that hides elements that will later be displayed using jQuery (e.g., an accordion). Won't these hidden elements remain hidden in browsers that support JavaScript but are not supported by jQuery? If so, should the code below be loaded after the jQuery library is loaded?
document.documentElement.className.replace(/\bjs\b/, '');
jQuery('html').addClass('js');
Is this beneficial? Is there any downside to using this code?
Thanks.
Hi Karl, thanks for this post, I have follwed every single recomendation of your post but I have a slide gallery inside the div I´m hidding and showing and after the toggle effect the gallery dissapear. Please check the page http://www.inversioneslacastellana.com/qsomos.php
there is a slide gallery at div="slide2" and is not showing anything.
What can I do in this case.
Thank you very much.
It should be "visibility: hidden" instead of "display:none" to make sure functions in $(document).ready works well.
This is just to simple and awesome! Thanks so much.
Why use an ID for "flash" though, since you will probably be using more than one of them per page. I used classes instead:
.js .flash
Awesome, though.
No reason to use an ID. It was just what I happened to use for the demo. No reason to use "flash" for the ID or class name either. Glad you enjoyed the entry!
Easiest fix that worked for me.
overflow: hidden;
http://shaneriley.com/cycle_faq_4/
Your solution made me feel stupid.... Can't believe I never thought of that. Thank you, I've been struggling with his for some time now.
Is it simpler to add $('html').removeClass('js'); after the document ready? (That is assuming everything you're trying to hide occurs on document ready) Or am I just imagining that'll work?
Hi ,
In my case I am using and xml file consist of a images path and rendering images from that file using a .Now I am using cycle.all.js plugin to slide those images and My images dispersed the first time page loads so I used this <div style="height: 433px;width: 800px;overflow: hidden" class="pics" id="s2"> i.e I applied a style on a div in which images are rendering specifying its witdh and height same as images and that problem is corrected but now facing another problem that is my images are loading slowly and first images slides before fully load .
==================================== Full Code :-
I tried the method, however, your said is not worked for me. :(
I use a div with class background-image: to designate each png file.
When not use below way, while my page first show, all image will show a flash as this page title said, after deploy below code, when open html page, the image could not show anymore, this is why?
Hi Jerry,
You misspelled "slideshow" in the line:
$('#slidesow').show();Note the missing "h."
I put together a jsfiddle page to give you another point of reference.
Hi Karl:
Thanks for your reply, Maybe I do not decribe my problem clearly. Please allow me to explain it as below.
I use JQuery Cycle Plugin to show 3 picture and texts as slides show. I use div to show image, and use a p to show text, and each image will have a related text. currently, these image and test can be shown as slide. however, when page load, I will see a flash of all image and all text are overlapped, after some time, as image and text has fade in/out, image and text can be shown as slide correctly. My problem is how to avoid all image and text shown incorrectly when page load. Thanks!
***I have added a space in each html tag of below code to avoid this page could not show source code correctly.****
Jerry, Please note the instruction for inserting html tags in your comments: "Use < instead of < and > instead of > in the examples themselves. Otherwise, you could lose part of the comment when it's submitted." There is a toolbar button just above the comment field to assist you in doing that.
Now to your question: you could provide a style rule like so:
And then bind a handler to window load to make those slides visible:
Hi Karl:
Thanks for your comments. I find that it still has some issue, Please check below code. You can see each div will have a element p to show some text, so when page load and use Cycle plugin to show these photo1/photo2/photo3, these element p's text will be overlapped, and they are shown as garbage text, even bind a handler to window load to make those slides visible, the text are all shown as garbage text, Thanks for your further help!
What I've done to avoid FOUC is:
· Set the body section as:
<body style="visibility: hidden;" id="id_body" onload="js_Load()">· Write the
js_Load()javascript function as:document.body.style.visibility='visible';With this approach the body of my web page keeps 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.
Know this is an old post but wanted to post this up for an option as well. It does cause multiple bodies but browsers will correct it. Feedback welome.
I had some issues implementing this in Chrome for some reason. The workaround that seemed to fix it involved changing the '$' to 'jQuery':
Hope that helps someone :-)
(Before anyone comments, yes jQuery is the only library I am using)
I had some issues first as adding the class with
jQuery('html').addClass('js');left the images invisible and the slideshow did not start. I'm using jQuery cycle btw.My solution was to remove the class when page has loaded, pretty much as someone suggested earlier. Works like a charm, tho I still ended up using overflow:hidden approach in css.