5d dynamic stylesheets

February 12, 2010 1:13 am | 7 Comments

This is the fourth of five quick posts about some browser quirks that have come up in the last few weeks.

You can avoid blocking rendering in IE if you load stylesheets using DHTML and setTimeout.

A few weeks ago I had a meeting with a company that makes a popular widget. One technique they used to reduce their widget’s impact on the main page was to load a stylesheet dynamically, something like this:

var link = document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = '/main.css';
document.getElementsByTagName('head')[0].appendChild(link);

Most of my attention for the past year has been on loading scripts dynamically to avoid blocking downloads. I haven’t focused on loading stylesheets dynamically. When it comes to stylesheets, blocking downloads isn’t an issue – stylesheets don’t block downloads (except in Firefox 2.0). The thing to worry about when downloading stylesheets is that IE blocks rendering until all stylesheets are downloaded1, and other browsers might experience a Flash Of Unstyled Content (FOUC).

FOUC isn’t a concern for this widget – the rules in the dynamically-loaded stylesheet only apply to the widget, and the widget hasn’t been created yet so nothing can flash. If the point of loading the stylesheet dynamically is to not mess with the containing page, we have to make sure dynamic stylesheets don’t block the page from rendering in IE.

I created the DHTML stylesheet example to show what happens. The page loads a stylesheet dynamically. The stylesheet is configured to take 4 seconds to download. If you load the page in Internet Explorer the page is blank for 4 seconds. In order to decouple the stylesheet load from page rendering, the DHTML code has to be invoked using setTimeout. That’s what I do in the DHTML + setTimeout stylesheet test page. This works. The page renders immediately while the stylesheet is downloaded in the background.

This technique is applicable when you have stylesheets that you want to load in the page but the stylesheet’s rules don’t apply to any DOM elements in the page currently. This is a pretty small use case. It makes sense for widgets or pages that have DHTML features that aren’t invoked until after the page has loaded. If you find yourself in that situation, you can use this technique to avoid the blank white screen in IE.

The five posts in this series are:

1 Simple test pages may not reproduce this problem. My testing shows that you need a script (inline or external) above the stylesheet, or two or more stylesheets for rendering to be blocked. If your page has only one stylesheet and no SCRIPT tags, you might not experience this issue.

7 Responses to 5d dynamic stylesheets

  1. This is a very useful technique (also Stoyan has coverd it recently) – when you have a website with few stylesheets. And on the home page there is used only one of them – you can just download ‘in background’ all others (it’s not related to @media print, but to stylesheets at all). This download can be done with attribute ‘disabled’ – you can cover its behavior in one of the next posts.

  2. I’m sorry, but I must disappoint you. Blocking continues even when using setTimeout. Take a look at an example that demonstrates the problem
    http://lab.fullajax.ru/ie-js-css-bridge/blocking.html

    I’ve found so far the only solution that does not block IE, is to use js-css bridge

    (function () (
    var d = document, style = d.getElementsByTagName ( “head”) [0]. appendChild (d.createElement ( “style”));
    style.type = “text/css”;
    style.styleSheet.cssText = “body {background: red}”;
    ))()

    Here is an example implementation
    http://lab.fullajax.ru/ie-js-css-bridge/nonblocking.html

  3. What about adding the unused stylesheets to the HEAD at window.onload event?

    Theoretically your HTTP request should not interfere with the other requests.

  4. @sunnybear – What’s the URL for Stoyan’s post?

    @Ruslan – I’m not seeing the blocking behavior.

    @Joris – Yes, loading them after the onload event also works. In some cases (such as widgets) it’s not desirable to wait that long.

  5. @Steve, please open http://lab.fullajax.ru/ie-js-css-bridge/blocking.html in FF and then in IE, and looking for difference.

    if you have any problem for determination difference, look at screenshot http://lab.fullajax.ru/ie-js-css-bridge/screenshot.png

  6. @Ruslan – isn’t this expected, because by having setTimeout() we have just delayed the IE to block rendering at a later point of time. So as soon as the node is parsed, IE probably stops the construction of rendering tree or repainting.

    And I think your solution works because you are inserting the style into the sheet and not referring to an external stylesheet. Probably if there was a external stylesheet reference in your solution, then IE would block rendering again.

  7. hi Steve,

    I tested the DHTML + setTimeout stylesheet page multiple times in IE7 on Vista with empty cache: the screen is blank until the stylesheet has finished loading.

    – Aaron