Zach’s ugly mug (his face)

Zach Leatherman

DOMContentLoaded Inconsistencies (in Browsers and JavaScript Libraries)

04 Dec 2008 Read in about 7 minutes

Quick Summary

  • Prototype and Dojo are the only major JavaScript frameworks that correctly time the DOMContentLoaded inside of an iframe in Internet Explorer. MooTools comes close and both YUI and jQuery both exhibit incorrect behavior.
  • Usually, browsers that have a native DOMContentLoaded event will fire it after both JavaScript and CSS (external script, link tags) have loaded. But Opera fires prior to CSS link tags loading.

We all know the problem, but we may not all call it the same thing. Every popular JavaScript library has its own name for the DOMContentLoaded event.

JavaScript LibraryEvent Name

But the naming scheme isn’t the only part about this event that’s inconsistent. There are a few hacks strewn around the net that have been bastardized (read: modified to the will of library authors) into each individual framework. These have been posted time and time again, but for post completeness are the following:

IE DOMContentLoaded HackDescription
doScroll by Diego PeriniUses a doScroll method call, which will throw an error if the ondocumentready event hasn’t fired on the primary document (take note of the usage of the word primary). Once doScroll doesn’t throw an error, it is assumed the DOM has loaded.
onreadystatechange and readyStateonreadystatechange “fires when the state of the object has changed,” and changes the readyState property of the object through the following states (not all apply to every type of element): uninitialized, loading, loaded, interactive, and complete. (source: MSDN) Usually set on the document object, or a script element (as used in the Script Defer method described next.
Script Defer by Dean Edwardsdocument.write’s a script tag with a defer attribute. Defer will cause the browser to delay execution of the script until the DOM has successfully loaded (using onreadystatechange on the script tag until its readyState is “complete”). Without defer, the browser would execute any script tag immediately.
HTC Behavior by Dean EdwardsMuch less popular approach using proprietary HTC Behavior files. Generally avoided due to the addition of an extra HTTP request to the page in order to download the external .htc file. As a side note, if using this approach, the "oncontentready" event will work better than the “ondocumentready” event used by Mr. Edwards.
Ghetto MethodOf course, the easiest way to do it is to put a script tag right above your ending </body> tag that triggers the event manually. This really only works if you have full control of the content, and isn’t really a library solution. Worth noting though.

Benchmark for Library DOMContentLoaded Implementations

Benchmark for Library DOMContentLoaded Implementations

I created a benchmark trying to answer the simple question: when does the DOMContentLoaded event fire? Each implementation has different effects, especially in iframes and with stylesheets.

What Works

The Internet Explorer hacks presented above are reliable when used on a standalone document (not inside of an iframe).

Mozilla Firefox, Safari, Chrome, and Opera all contain a native DOMContentLoaded event that each framework uses to consistently fire at the correct time. So, it isn’t even worth summarizing the results for tests in every browser with a native DOMContentLoaded event, except Opera. Opera took a different design approach with their DOMContentLoaded event (certainly not wrong, just different), which we’ll analyze below.

Internet Explorer inside an Iframe

All libraries below did no branching based on IE versions, all used the same method for IE6, IE7, or IE8. I performed no tests in IE8, however.

JavaScript LibraryMethodWaited for:
<body> <script><head> <script><link> CSS<img>
YUI 2.6.0doScroll, setTimeoutIncorrect: Fires almost immediately (~20ms)
jQuery 1.2.6window onloadXXXX
Prototype DeferXXX
MooTools 1.2.1doScroll and set innerHTML, setTimeout*XX
Dojo 1.2.0Script DeferXXX
IEContentLoadeddoScroll, document.onreadystatechangeIncorrect: JavaScript error.
addDOMLoadEventScript DeferXXX
  • For some reason, not only did the MooTools library not wait for the body script to trigger DOMContentLoaded, the body script never executed at all.

The most important takeaway from this blog post are the successful methods of faking DOMContentLoaded in Internet Explorer. The obvious library winners here are Prototype and Dojo, with the addDOMLoadEvent script also exhibiting correct behavior. MooTools is a close runner up, and I would be interested to find out why it didn’t execute the body script (that’s left for another day, or perhaps a generous commenter).

Opera 9.6

JavaScript LibraryMethodWaited for:
<body> <script><head> <script><link> CSS<img>
YUI 2.6.0Native DOMContentLoadedXX
jQuery 1.2.6Native DOMContentLoaded + Code to wait for StylesheetsXXX
Prototype DOMContentLoadedXX
MooTools 1.2.1Native DOMContentLoadedXX
Dojo 1.2.0Native DOMContentLoadedXX
IEContentLoadedN/A to OperaXXX
addDOMLoadEventNative DOMContentLoadedXX

As you can see above, Opera typically will fire DOMContentLoaded prior to stylesheets loading successfully (ignoring the jQuery specific code to provide consistency cross-browser)

Thanks to Adam Koch for first pointing me in the direction of jQuery in an iframe ignoring DOMContentLoaded in IE.

Update: There is an open ticket for YUI on Sourceforge, and I’ve opened a ticket for jQuery on their Trac site.

1 Comment

➡ Load Disqus to Leave a Comment ⬅

a very nice collection of info and comparison on the current state of the "onload" problem.

Just to clarify, IEContentLoaded is an IE specific method based on MS information and at the time of publishing (and jQuery inclusion) it was known to not work for iframes (the reason is still unknown to me though).

This is the reason I use the "onreadystatechange" event on IE if the target of the check is an iframe while I use the "doScroll()" trick on the main document.

I never suggested to use my method alone, since it was released the IEContentLoaded page clearly states:

meant to be used as an IE alternative in other fine scripts trying to fix the window onload problem

and link to other developer's scripts that you also mention in your test and description.

There is nothing bad in mixing those scripts, for example use the "doScroll()" for the main document and the HTC method or Dean/Mathias document.write for iframes.

In other words it is up to the implementors to spice or cut their methods depending on their libraries/framework needs.

IEContentLoaded, as of today, is correctly implemented as I originally intended only in jQuery, Prototype, ExtJS and in both sIFR and SwfObject.

I would add "BrotherCake" body detection to your list of methods since that is really the only needed cross-browser moment if you just need to attach your widgets to the body.

Keep up the good work,