DOMContentLoaded gotcha with external stylesheets
Sunday, July 8, 2007 10:26:49 PM
A user came in to the #webapps channel today complaining that Opera didn't show his accordion menu properly. In fact it only worked if the stylesheets he used were included inline, rather than referred to as external stylesheets.
After some digging around, including downloading the source of jQuery and Interface it turned out that the Accordion effect was trying to read CSS attributes and setting them again.
jQuery(this) .css('height', jQuery(this).css('height')) .css('overflow', 'hidden');
Since this was started after DOMContentLoaded which in Opera fires before the CSS is loaded and applied, it made the elements keep the default values rather than those set in the CSS Stylesheet.
The solution to this specific problem was to avoid using DOMContentLoaded event when starting scripts that will eventually use CSS attributes, the startup was then wrapped in
DOM compliant browsers.
The moral I guess, is to watch out when using $(foo).ready in jQuery, and probably go for (on)load for anything that relies on CSS attributes being applied
The question here is though. when should DOMContentLoaded really be fired. The scarce Mozilla documentation states:
DOMContentLoaded Fired on a Window object when a document's DOM content is finished loaded, but unlike "load", does not wait till all images are loaded. Used for example by GreaseMonkey to sneak in to alter pages before they are displayed. Does not appear to be dispatched to a Browser object (why?)
Which only explicitly mentions images, so I guess waiting for external styles is correct behaviour.
The HTML5 documentation at http://www.whatwg.org/specs/web-apps/current-work/#the-end doesn't seem to mention anything about wether or when style attributes should be appended to the elements in the documen before the DOMContentLoaded event is fired.
The name doesn't really indicate that one should wait for CSS -- Except when CSS is used to alter content of the DOM, like the content:-attribute -- Or possibly when using pseudo elements, so again, probably correct to also wait for external stylesheets.
However, I haven't peeked into the Mozilla Firefox code to see what it really waits for, and the original intention to have something else than onload that would fire before external data is loaded would suggest that DOMContentLoaded would fire before external CSS is loaded.
So, should Opera change behaviour, should Mozilla Firefox change behaviour, should the various events throughout a loading process be more fine-grained, and maybe throw events when various types of externally linked elements are being loaded? Suggestions?
Here's a test that says the Mozilla Firefox way is correct: http://people.opera.com/nicolasm/test/domcontentloaded.html