Conditional comments block downloads

I came across this blog post (via @pornelski and @souders) where Markus has stumbled upon a case where an IE6-only stylesheet included with a conditional comment blocks the downloads in IE8. Whaaat?

I had to dig in. To give you a summary: turned out that any conditional comment, not only for an extra CSS, will block further downloads until the main CSS file arrives. Also the solution offered on the blog post (using X-UA-Compatible) seems to be more of an error due to an accidentally left comment.

Check out the tests.

Base page

The first test is the base page. It follows a pretty common style pattern - CSS at the top, a bunch of images in the middle, JS at the bottom.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<html>
<head>
    <title>The base page</title>
    <link type="text/css" rel="stylesheet"
          href="http://tools.w3clubs.com/pagr/1.expires.css">
</head>
<body>
<p>
    <img src="http://tools.w3clubs.com/pagr/1.expires.png" alt="1">
    <img src="http://tools.w3clubs.com/pagr/2.expires.png" alt="2">
    <img src="http://tools.w3clubs.com/pagr/3.expires.png" alt="3">
    <img src="http://tools.w3clubs.com/pagr/4.expires.png" alt="4">
</p>
<script type="text/javascript"
        src="http://tools.w3clubs.com/pagr/1.expires.js"></script>
</body>
</html>

The waterfall produced by WebPageTest looks like so:

base page

The page is here, the results of the WebPageTest's test are here.

Conditional IE6 stylesheet

Adding a second stylsheet to the head like so:

<head>
  <title>base page</title>
  <link type="text/css" rel="stylesheet"
        href="http://tools.w3clubs.com/pagr/1.expires.css">
  <!--[if IE 6 ]>
    <link type="text/css" rel="stylesheet"
          href="http://tools.w3clubs.com/pagr/2.expires.css">
  <![endif]-->
</head>

Turns out that this conditional comment blocks further downloads until the main CSS arrives.

Test page, test results, waterfall:

CC style page

Just like that the total page to onload time went up from 1 second to almost 1.3 seconds. Ouch.

And this is because of an IE6 stylesheet, which IE8 has no use for. My wild guess is that IE needs to parse through those conditional comments and treats them sort of like inline script. And we know that inline scripts following a stylesheet tend to block.

Conditional markup

What if we don't include IE6 specific stylsheet, but use the conditional comments to write different body tags with different class names, as described by Paul Irish.

<!--[if IE 6]> <body class="ie6"> <![endif]-->
<!--[if !IE]><!--> <body> <!--<![endif]-->

Turns out that these markup conditional comments will also block downloads until the CSS arrives.

Test page, test results, waterfall looks as bad (the same blocking).

Browser-sniffing comments

I blogged about this a few days ago - using conditional comments to do the browser sniffing and include appropriate CSS - one for normal browsers and a complete alternative for IE6,7.

<head>
  <!--[if lte IE 7]>
    <link type="text/css" rel="stylesheet"
          href="http://tools.w3clubs.com/pagr/2.expires.css">
  <![endif]-->
  <!--[if gt IE 7]><!-->
    <link type="text/css" rel="stylesheet"
          href="http://tools.w3clubs.com/pagr/1.expires.css">
  <!--<![endif]-->
</head>

Turns out this is OK to do. The conditional comments are processed before the download is initiated, so there't nothing to block on after the stylesheet. Yeey!

Test page, test results, waterfall looks like the first one for the base page.

X-UA-Compatible not a solution

The blog post suggested using the X-UA-Compatible meta tag to say that the UA is the latest IE possible.

<meta http-equiv="X-UA-Compatible" content="IE=edge">

It didn't work for me.

Test page, test results, waterfall like the second (the blocking) one.

Looking closely and thanks to the screenshots digging out the original test page I noticed that it contains a dangling comment. Putting that dangling comment in a test page, and the blocking effect was gone. But this is a bug. In fact the comment shows up on the page! My wild guess is that this improper comments invalidates the following one and that's why there's no blocking. I guess that IE6 will not load the stylesheet, but I didn't test.

So my tests - with X-UA meta tag (results) and with comment bug (results)

Conclusions, conclusions

To summarize, if you worry about performance, don't use conditional comments.

There might be an exception when you put a script in the head after the CSS - then there are two blocking things, so the effect of the conditional comment is not visible. But that's still bad for performance, there's still blocking.

It's OK to use the browsers-sniffing comments approach, provided of course, that there's no other CSS file before the sniff. If there is one, it will block.

Best - just use _ and * hacks, go with a single CSS and forget sniffing.

Update: empty conditional comment

Thanks to Markus who kept looking into the extra conditional comment comes a solution: an empty conditional comment early on solves the blocking issue.. By "early on" I mean before the main CSS which caused the blocking.

I did two more tests to validate the solution and it absolutely works.

One test has empty comment + conditional comment for writing Paul's body tags. The empty comment (aka the solution) is right before the blocking CSS file.

<head>
    <title>base page</title>
    <!--[if IE 6]><![endif]-->
    <link type="text/css" rel="stylesheet"
          href="http://tools.w3clubs.com/pagr/1.expires.css">
</head>

<!--[if IE 6]> <body class="ie6"> <![endif]-->
<!--[if !IE]><!--> <body> <!--<![endif]-->

Test page, webpagetest results. Works as advertised, no more blocking.

The second test uses empty comment and conditional stylesheet. In this case I even put the empty comment way at the top. Sort of like declaring upfront - hey this page uses conditional comments and the empty comment is the solution to the blocking effect.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">
<!--[if IE 6]><![endif]-->

<html>
<head>
  <title>base page</title>
  <link type="text/css" rel="stylesheet"
        href="http://tools.w3clubs.com/pagr/1.expires.css">
  <!--[if IE 6 ]>
    <link type="text/css" rel="stylesheet"
          href="http://tools.w3clubs.com/pagr/2.expires.css">
  <![endif]-->
</head>

Test page, webpagetest results. No more blocking :)

Answering Andrea's question - what it if you have several conditionals - for IE6, IE7 and so on, I did one more test with two conditional CSS files. Turns out it's fine, as long as there's one conditional comment before the CSS. I actually updated the comment so it checks for all IE versions.

Test page, results, code:

<!--[if IE]><![endif]-->
<html lang="en">
<head>
    <title>base page</title>
    <link type="text/css" rel="stylesheet"
          href="http://tools.w3clubs.com/pagr/1.expires.css">
    <!--[if IE 6]>
        <link type="text/css" rel="stylesheet"
              href="http://tools.w3clubs.com/pagr/2.expires.css">
    <![endif]-->
    <!--[if IE 7]>
        <link type="text/css" rel="stylesheet"
              href="http://tools.w3clubs.com/pagr/3.expires.css">
    <![endif]-->
</head>

In conclusion #2... conditional comments cause CSS to block. The workaround it to have an extra empty comment before the blocking CSS, or, to be safe, right after the doctype. Even better - don't use conditional comments at all. Except for browser-sniffing and loading two complete and completely separate CSS files, not just the IE fixes.

This entry was posted on Sunday, May 23rd, 2010 and is filed under CSS, performance. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.


Get notification for future posts: follow me on Twitter or subscribe to my RSS feed

Somewhat related posts

14 Responses to “Conditional comments block downloads”

  1. Andrea Giammarchi Says:

    what if you put the if IE 6 or lte 7 at the end of the page after the body?

    That would be “just a comment” for standard browsers, a CSS “fixer” for IE 6 or 7.

    It’s quite common technique to write a standard CSS file and then overwrite some selector to fix IE6 inconsistencies, the fact we have to respect the order means redundant files/bandwidth for the server, isn’t it?

  2. Stoyan Says:

    Andrea, that would be possible, but will not allow the page to render progressively in IE67. The browser waits for all CSS to arrive (all but Opera do) before starting to render (test: http://www.phpied.com/rendering-styles/). That means IE67 users will look at a blank page till the final css (and therefore all JS) is downloaded.

    That’s why to fix ie6 inconsistencies, the _ hack (and * for IE7) is your friend :) It stays in the same selector and is easy to spot and problematically parse and delete once IE6 is no longer around

  3. Francis Says:

    Hi, Nice one.

    but luckily I prefer to use server side browser sniffing and then include the corresponding css file,

    works like charms.

    Thanks for the insight

  4. Markus LeptienM Says:

    Hi Stoyan!

    Thanks for your comments and correction! I updated my blog entry, http://webforscher.wordpress.com/2010/05/20/ie-6-slowing-down-ie-8/ now with a different solution.

    Kind regads,
    Markus

  5. Dan DeFelippi Says:

    Thanks for the update on this. I generally only use conditional comments to load a PNG fix. It should be fine to move it before all other files in the head thus negating the slowdown.

  6. Andrea Giammarchi Says:

    Stoyan, I thought the problem was to avoid IE8 slow down … I am a bit sick to care that much about users/companies stuck in the past with their buggy+un-secure browsers (and for no valid reasons) but you are right, that is a side effect to mention :-)

  7. Stoyan Says:

    Andrea, yes, the problem is slow down in IE8. But the problem is caused by a solution for IE6 or 7 suggested by the vendor of IE8 :)

    Anti-pattern: solution that causes more problems than it solves :P

  8. rosamez Says:

    “Best - just use _ and * hacks, go with a single CSS and forget sniffing.” Dear sir, I regret to say that your advice here is astonishingly stupid so I strongly recommend you not to do frontend development at all or at least remove this offending line from your post. Thank you.

  9. Rob Larsen Says:

    My variation of Paul’s pattern works out of the box:

    http://www.webpagetest.org/result/100608_0431442088c94bfba54f79e8ad027165/

    Instead of applying classes to the body, I apply them to the HTML element. No need for empty comments.

  10. Stoyan Says:

    @rob ahaa! good one

  11. NICCAI Says:

    I’m a big believer in conditional comments around the body, so I will definitely be recommending Rob’s fix internally at Move. Although I’d put it nicer, I’d agree that going with the * and _ route is probably not a great idea. It’s far less readable for those that don’t have a full understanding, and it may not be as viable long-term (I know what you’re thinking). That said, having everything in one CSS is the way to go from both a performance and a maintenance perspective. Thanks Stoyan and others for this.

  12. bz Says:

    Here is my bloated variation of this trick:

    http://textsnip.com/3ef57a

  13. HansBKK Says:

    Here’s the start of a method to enable developing multiple “full alternative” versions of browser-targeted stylesheets rather than the usual IE override technique. It uses diff, plus the Compass authoring toolset a “CSS meta-framework” (which in turn is based on Sass). This allows you to maintain ALL your style code in a single source file, and compile/output different versions of standard CSS by using variables, conditionals and other real programming features within your CSS. Feedback please - hansbkk [at] gmail

    http://groups.google.com/group/compass-users/browse_thread/thread/23f81314c706d01

  14. Erik Reppen Says:

    The ideal solution, IMO, is to avoid browser targeting for all but IE 6 which is filtered nicely with * html. Unlike hacks, it takes advantage of fundamental flaws in IE6’s idiot-version of the DOM so it’s unlikely new features in the future will cause these statements to break anything.

    If you’re on a large team where not everybody knows enough to avoid IE 7 issues with non-browser-specific declarations, I don’t see any problem with a one-time browser sniff to target IE 6 and 7 problems. There’s no practical way to test by method for CSS problems and I find it considerably less hacky than touching IE-proprietary technology that (as we can see) makes an incredibly stupid oversight in turning comments into something other than a simple flag to tell the parser to ignore the contents.

    Also, branching CSS sheets makes maintenance a PITA. Browser targeting works best when the bad-browser declarations are side by side with the general declarations where everybody can see them and the targeting is handled in a consistent manner that makes it easy to yoink when Microsoft’s garbage browsers are finally no longer a going concern.

Leave a Reply