Novemberborn, Straight lines circle sometime

On DOM Load (and CSS, too)

The discussion on document load detection is more than two years old. The accepted solution for IE looks pretty much like this:

document.write('<scr'+'ipt defer src="//:" '
  + 'onreadystatechange="if(this.readyState==\'complete\'){dojo._loadInit();}">'
  + '</scr'+'ipt>'

(As you can see I took this from Dojo)

Unfortunately this solution is broken. It relies on the defer attribute, which causes the script to change its readyState to complete after the document has finished loading. defer, however, doesn’t always work correctly. If the innerHTML of a descendant of the body element is changed by an inline script, the script may not be deferred properly. This bug cannot always be reproduced – I’ve seen it occur only a few times while others report it happening on every second page load. However, I did find a way to force its appearance. The bug can be triggered by alert()ing right after changing the innerHTML. See also a test case.

So, without the defer trick, what else can we use to detect DOM load in IE? Diego Perini found a pretty cool solution. If you call document.documentElement.doScroll('left'); before the document has loaded, an exception is thrown. Call it every couple of milliseconds until there’s no exception, and you know the document is ready. Diego has also done a superb job of testing his solution, ensuring that it works as expected.

With IE covered, let’s have a look at document load in other browsers. Mozilla 0.9.4 introduced a DOMContentLoaded event for the document object. Opera 9 also supports this event. Since about two months WebKit supports it as well, but only in the nightly builds. Konqueror is in the same situation, and will support it starting with version 4.0. For WebKit and Konqueror, which do not yet support the DOMContentLoaded event, you can poll the readyState of the document, as explained by Dean Edwards.

We can say that document load is covered (again). However, it isn’t sufficient if your script relies on the CSS being applied. Opera, WebKit and Konqueror load CSS and JavaScript in parallel (all CSS is loaded before being applied, however). This means that the document may have finished loading, and your JavaScript may have executed, before the CSS is fully loaded and applied. sIFR relies on CSS, which means that document load may be too early. Preferably there’d be a CSSApplied event, but in lieu of that, we can detect CSS application ourselves.

The trick is to insert an empty element into the body, which has a style property set in the external style sheet. If you insert this element on document load, and poll every couple of milliseconds until the style property can be retrieved using the computed style, you know that the external style sheet has been applied.

I’ve implemented the hacks discussed in this post in sIFR r339. See also hacks.pageLoad under sifr.js:

function checkStyle() {
  dummy           = dom.create("div");
  dummy.className = CSS_DUMMY;
  dom.getBody().appendChild(dummy);
  pollStyle();
};

function pollStyle() {
  if(dom.getComputedStyle(dummy, 'marginLeft') == '42px') afterStyle();
  else setTimeout(pollStyle, 10);
};

function afterStyle() {
  if(dummy && dummy.parentNode) dummy.parentNode.removeChild(dummy);
  dummy = null;
  fire(null, true);
};

And the CSS:

.sIFR-dummy { 
  width: 0px;
  height: 0px;
  margin-left: 42px;
  z-index: 0;
}

link | javascript sifr3 | 6 December 2007, 22:40


Comments

  1. Mark, happy to see the “doScroll()” trick landing in sIFR3, also I understand it doesn’t offer a complete solution for the CSS problem you mentioned, at least it avoids having to use “document.write” and the “defer” trick.

    An alternative way of solving the CSS problem in Opera is discussed in this thread:

    http://groups.google.com/group/jquery-dev/browse_thread/thread/ad7e754c0a10f88a/

    I proposed a solution that “seems” to work for detecting that stylesheets are fully loaded and applied in Opera. Hope it can work the same for Webkit/Konqueror.

    Basically it seems the stylesheets “disabled” property is kept “false” until after the style has been fully applied, don’t remember where I read it…

    The bad news on my “doScroll()” trick is that it does not work as expected in IFRAMEs.

    You should be warned about this deficiency to let you make the right decision about including this in your final sIFR3 project or take a different path.

    Diego

    Diego Perini | 8 December 2007, 04:24 | link

  2. Has anyone tried mashing up sIFR 3b2 with Google’s Website Optimizer? I’m currently investigating a solution that will allow us to move forward with this form of testing/replacement, but at the moment it is not sIFR-friendly. :(

    Mark, what comes to mind for possible solutions?

    Mike Reid | 18 January 2008, 22:25 | link

  3. Uhm, I don’t really know what you’re talking about Mike. Care to fill me in? :)

    Mark Wubben | 18 January 2008, 23:04 | link

Leave your comment

Please keep it polite and on topic. Yes, your e-mail address is required, but it's kept private. HTML is not allowed in the comments but you can use Markdown. Non-contributing comments run the risk of being removed. Especially if the website seem “fishy”. Spammers, beware.

(required)
(required, kept private)
(optional, but let's share it!)
(required)

Remember my details


Novemberborn: Extra

About the author

Mark Wubben is a hacker/writer in Enschede, the Netherlands.

Read more about Mark...

Go to

Jobs (NL)

Xopus zoekt programmeurs! Verbeter de code en win!

Please donate

If you like sIFR, please consider making a donation so I can spend more time on it. Thank you.

sIFR Documentation

See the documentation for sIFR 2 and sIFR 3.

Subscribe