DOMContentLoaded gotcha with external stylesheets
Sunday, 8. July 2007, 22:26:49
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.
interface/accordion.js:
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
window.onload(MSIE),
window.addEventListener("load",function,false);(Firefox) or
document.addEventListener("load",function,false);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
Correct behaviour?
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
Also Opera would be used as IE not now.
I know changes are growing however, why ruin something good
By zenya, # 8. July 2007, 22:56:05
By nicomen, # 8. July 2007, 22:57:01
now it's very difficult to make changes using their templates.
My online friend Diem use to do my blog theme for me since he is trained in grapic art and doing web pages and when I changed to the new template I have now he could not use the same CSS as it won't work with the new templates
Also before Opera would be reconized as IE now it isn't as far as I can see.
By zenya, # 8. July 2007, 22:59:49
The second issue is quite easy to fix: Press right mouse button on any page and select Edit Site preferences. There you can tell Opera to identify as MSIE or Mozilla Firefox for any given site. Useful for some pages. But of course, if a page doesn't work in Opera because of browser sniffing, you shuold file a bug to the website.
Oh, btw. both issues are off-topic ;-P
By nicomen, # 8. July 2007, 23:05:31
I just liked the option of not having sidebars and to have a full window for photos not the side window for my album photos showing.
I am sorry if I am interrupting you, that's why I wrote a pm not to take up your blog time..
BTW I won't post in the forums since some of the people in there have huge egos and lack of tollerance
By zenya, # 8. July 2007, 23:11:50
This time I just copy-pasted your pm though, thanks again
By nicomen, # 9. July 2007, 00:11:20
Just a small comment. CSS does not alter the DOM in any way, even when using the
contentproperty.By hzr, # 9. July 2007, 16:50:37
Browsers (except Opera) won't render on-screen until all the stylesheets have loaded. I like Opera's interpretation as I see the page content earlier. Styles follow after they get loaded.
In Opera you can specify to "redraw after X seconds" in the advanced preference->browsing->loading. I'd rather see an unstyled table/page/whatever after 1 second than waiting for the content until all external stylesheets are loaded. As hzr pointed out, the DOM won't get altered by the CSS, so DOMContentLoaded is fired correctly by Opera.
By anonymous user, # 9. July 2007, 17:40:04
By hallvors, # 10. July 2007, 15:36:27
Wouldn't that make Opera slower in response? Waiting for external content/stylesheets, that is.
By anonymous user, # 10. July 2007, 16:15:49
http://www.mail-archive.com/public-webapi@w3.org/msg02176.html
By nicomen, # 10. July 2007, 17:31:01
I think Opera fires the event when it should. When DOMContentLoaded fires, the browser may not have loaded any styles, external content, or reflown the document. If a script needs to wait for it, then it should wait for load. If the browser waits for styles then it'll introduce more lag.
By xErath, # 10. July 2007, 19:58:21
And stylesheets are part of the DOM, as you can access them from it. So... there still is the question if browsers should wait for the stylesheets to be loaded, but that CSS doesn't chnage the DOM at all... I think that's too strong a statement...
By _Grey_, # 10. July 2007, 22:35:13
But on topic, why not give developers an option? I don't see why browsers should only provide one or the other if it's not too difficult to implement both. Create something like a StylingApplied event that fires after the DOM has been constructed and CSS has been applied to everything. Options are good!
By HeroreV, # 11. July 2007, 04:45:29
I think that Opera does fire the event at the correct time. I would imagine that if any other browser had the feature that Opera does (rendering the page before stylesheets are fully loaded) then they would run into the same issue.
However, I agree with hallvors: compatability concerns outweigh whatever beliefs I have about how I would have written the spec.
The other, more complex solution, would be to have opera fire the DOMContentLoaded event when it currently does, but then have the execution stall if it trys to access/write to a CSS attribute untill all CSS has been loaded.
By anonymous user, # 11. July 2007, 14:38:24
If it's important to know when stylesheets have loaded, then separate "onload" type event handlers need to be registered. Images already support that, so I don't see why stylesheets couldn't either. Maybe they already do?
That gives much more precise and fine-grained control. If it is decided that DOMContentLoaded should wait for stylesheets to load, then that simply means that another event that does what DOMContentLoaded is supposed to do would be needed. Which would be quite perverse, IMO!
By Andrew Gregory, # 13. July 2007, 03:13:58
I guess I agree that DOMContentLoaded should be exactly that, and that seems to be what HTML5 defines it as, but when running that test case with Mozilla Firefox which are the people actually inventing that event AFAIK, then external stylesheets are waited for, although it supposedly doesn't. *confused*
By anonymous user, # 13. July 2007, 09:43:59
By shoust, # 17. July 2007, 13:03:17
Some sites like Yahoo! etc. have very big stylesheets so waiting for CSS files before DCL event will only slow down things. You can already use load event if you want to make sure CSS files are loaded but what if you want to run script as soon as the DOM is loaded (in userjs etc.) ? Then there will be no solution
By AyushJ, # 23. July 2007, 17:58:37
By little_lemur, # 24. July 2007, 21:20:49
By little_lemur, # 24. July 2007, 21:21:47
If people find a use case for finding when the CSSOM is finished from external sources, then browsers should try to provide a separate event for that. Say a DOMCSSLoaded event...
Why do I say that? Because I've found a need for DOM manipulation (particularly adding events on stuff) far more common than a need to work on the style sheets, and for some sites the style sheets can be unproportionally large compared to the HTML source.
By liorean, # 28. July 2007, 09:44:33