How do you detect when CSS styles have loaded?

February 8th, 2009 Alex Moffat Posted in GWT | 3 Comments »

As part of the development of Blueprint we use a GWT generator that embeds CSS data in the compiled JavaScript. At runtime the CSS is inserted directly into the web page inside a <style> element. This means the browser doesn’t have to download any additional CSS resources and because of the strong naming of the generated JavaScript any changes to the CSS contents will be picked up automatically by the client. However, …

this means you must recompile the application each time you change the CSS. If you use hosted mode this will happen anyway whenever you refresh the page, so experimenting with CSS changes in this situation is easy. But, if you don’t want to use hosted mode, or can’t because the browser you want to test with isn’t the one hosted mode supports on your platform, another approach is needed. To support this use case the CSS injector can be put into development mode and it will then insert <link> elements instead of directly inserting the CSS data.

When you are using direct injection via <style> elements then as soon as an element is inserted into the dom the styles it provides are available. Using <link> elements means there may be a delay after the element is inserted before the linked url is loaded and the styles are ready to use. If you have code that depends on having style information available this will cause problems. To work around this, and remember it’s only a problem in development situations, I need to be able to detect when the styles loaded via a <link> element are available so that any code that depends of style information can be invoked at the right time.

After some experimentation I’ve found a couple of ways to determine when styles are loaded, one which works on Firefox 3 and Safari and one which works on IE6 and IE7. Both rely on checking the link element at regular intervals but I don’t regard that as a problem because this is for use in development situations only. For Firefox 3 and Safari I use the following code (updated based on comments below)


    protected native boolean linkIsLoaded(LinkElement le) /*-{
        try {
            return le.sheet && le.sheet.cssRules;
        } catch (err) {
            return false;
        }
    }-*/;

while for IE6 and IE7 I use


    protected native boolean linkIsLoaded(LinkElement le) /*-{
        try {
            return le.readyState == "complete";
        } catch (err) {
            return false;
        }
    }-*/;

As you can probably guess from the fact that there are two methods with the same name here deferred binding is used to select the correct version at compile time.

3 Responses to “How do you detect when CSS styles have loaded?”

  1. Thomas Broyer Says:

    Er, typeof(…) returns a string, so you should compare it to “undefined”, or just test le.sheet&&le.sheet.cssRules (or “sheet” in le && “cssRules” in le.sheet).

    And for IE, instead of periodically checking le.readyState, you should be able to subscribe to the onreadystatechange event (or even onload and/or onerror).
    http://msdn.microsoft.com/en-us/library/ms536957(VS.85).aspx
    http://msdn.microsoft.com/en-us/library/cc197055(VS.85).aspx

    Actually, I haven’t checked but I believe you should be able to subscribe to the onload (and/or onerror) event whichever the browser.
    See http://enhance.qd-creative.co.uk/2008/12/06/the-magic-of-onload-revealed/ which suggests using $(’link[rel=stylesheet]‘).whenLoaded(), where whenLoaded() is an extension that uses .load() on each matched element and only fires when all of them are loaded (and where .load() in jQuery seems to just listen to the onload event)

  2. Oops, what a silly mistake. I was originally testing ie.sheet && ie.sheet.cssRules without success. I’ll go back and try again. Listening for onreadystatechange or onload is, as you say, a better choice if you need to be notified as soon as the styles load but it isn’t necessary for my use case, I can live with the periodic checks when running in development mode.

  3. Yep, on Safari and FF3 “return le.sheet && le.sheet.cssRules” works fine. I still need the try / catch block because Firefox throws an exception on the le.sheet.cssRules statement until the styles have actually loaded.

Leave a Reply