Zach’s ugly mug (his face) Zach Leatherman

DOMContentLoaded Inconsistencies (in Browsers and JavaScript Libraries)

December 04, 2008

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 Library Event Name
YUI DOMReady
jQuery ready
MooTools domready
Prototype dom:loaded
Dojo addOnLoad

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 Hack Description
doScroll by Diego Perini Uses 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 readyState onreadystatechange “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 Edwards document.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 Edwards Much 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 Method Of 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 Library Method Waited for:
<body> <script> <head> <script> <link> CSS <img>
YUI 2.6.0 doScroll, setTimeout Incorrect: Fires almost immediately (~20ms)
jQuery 1.2.6 window onload X X X X
Prototype 1.6.0.3 Script Defer X X X
MooTools 1.2.1 doScroll and set innerHTML, setTimeout * X X
Dojo 1.2.0 Script Defer X X X
IEContentLoaded doScroll, document.onreadystatechange Incorrect: JavaScript error.
addDOMLoadEvent Script Defer X X X
  • 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 Library Method Waited for:
<body> <script> <head> <script> <link> CSS <img>
YUI 2.6.0 Native DOMContentLoaded X X
jQuery 1.2.6 Native DOMContentLoaded + Code to wait for Stylesheets X X X
Prototype 1.6.0.3 Native DOMContentLoaded X X
MooTools 1.2.1 Native DOMContentLoaded X X
Dojo 1.2.0 Native DOMContentLoaded X X
IEContentLoaded N/A to Opera X X X
addDOMLoadEvent Native DOMContentLoaded X X

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.


< Newer
Scare Your Visitors with this JavaScript Gravatar Plugin
Older >
Dear IE6: Please Cache my Images.

Zach Leatherman IndieWeb Avatar for https://zachleat.com/is a builder for the web at IndieWeb Avatar for https://cloudcannon.com/CloudCannon. He is the creator and maintainer of IndieWeb Avatar for https://www.11ty.devEleventy (11ty), an award-winning open source site generator. At one point he became entirely too fixated on web fonts. He has given 79 talks in nine different countries at events like Beyond Tellerrand, Smashing Conference, Jamstack Conf, CSSConf, and The White House. Formerly part of Netlify, Filament Group, NEJS CONF, and NebraskaJS. Learn more about Zach »

1 Comment
  1. Diego Perini Disqus

    09 Jan 2009
    Zach,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 problemand 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,Diego
Shamelessly plug your related post

These are webmentions via the IndieWeb and webmention.io.

Sharing on social media?

This is what will show up when you share this post on Social Media:

How did you do this? I automated my Open Graph images. (Peer behind the curtain at the test page)