I’ve been working on a small JavaScript library that is built using Prototype, and discovered a small quirk that caused Opera and Safari to respond differently than IE and Firefox when using the dom:loaded event with the document.observe function.
According to the Prototype documentation dom:loaded will “fire immediately after the HTML document is fully loaded, but before images on the page are fully loaded.” My script manipulates a set of images that are on the page, and I needed to process each image before the page loaded. If I waited until the document had fully loaded, then a flicker would occur in a couple of browsers. Unfortunately, it wasn’t happening in every browser so this made it difficult to diagnose.
Initially, my approach was to first intercept the images, hide them (save for the first image), and instantiate my object all before the DOM had finished actually loading the images. This is basically what I was doing:
document.observe(’dom:loaded’, function() {
// error checking, reading images into an array here
images.each(function(i) {
if(i != images.first()) {
i.hide();
}
});
// apply some specific margin styles here
});
The end result worked well - it behaved exactly as I had anticipated across IE6, IE7, Safari, Opera, and Firefox but the problem didn’t occur until I uploaded everything to a web server and began running tests across these same browsers. That’s when I found an ugly bug: Opera appeared to be completely ignoring all of the initial processing. Safari occasionally demonstrated the same exact error, but it was inconsistent - sometimes it worked, sometimes it didn’t.
Rather than try to hack the code to get it to bend just enough for Opera, I wanted to investigate it and figure out exactly what was going wrong. Sadly, Opera doesn’t have a nice DOM debugging console (at least not that I found), so I had to resort to creating some test cases to pinpoint the issue.
First, the reason that the error didn’t show its face until the script was running on a web server is because the images were stored locally so there was close to no time required for the images to load - on a web server, that’s obviously different.
Secondly, regarding the script, I’m not 100% positive that this is the problem, but it’s as close as I could come based on the results of my tests. What I found is this:
Earlier, I mentioned that the dom:loaded event is triggered prior to when the images are loaded, right? Well, I was initially trying to access the image.height property during this processing. Whereas the other browsers were already parsing each image’s properties, Opera was not. From what I gather, the other browsers are loading up the properties of each image prior to actually displaying them, and Opera is delaying all of this until the dom:loaded event has completed. Basically, this makes it impossible to process any of the images until they are visible on the screen.
After discovering this, I made some changes to the code. I was somewhat reluctant to do this at first because I didn’t wanna sacrifice some of the slight performance issues that would come as a result of the fix; however, the cost of flexibility outweighs the minimal performance decrease, in my opinion. Here’s what I did:
document.observe(’dom:loaded’, function() {
// error checking, reading images into an array here
images.each(function(i) {
if(i != images.first()) {
i.hide();
}
});
});
Event.observe(window, ‘load’, function(evt) {
// apply some specific styles to the images here
});
Ultimately, this still allows me to hide all of the images prior to them being displayed so none of the actual visuals are affected, but I delay the image processing until the images are actually loaded by the browser. This proved to completely fix the bug in Opera and also stopped the inconsistency issues in Safari.
As I mentioned before, I’m not 100% positive that the results of my testing are correct, but it seems to be close based on the results. Additionally, this fix ended up addressing the cross-browser quirks so I’m content with the solution. If any of you are familiar with the issue that I was having, or have had any similar experience, leave me a comment.
Later, I’ll go more in depth on this library that I’ve been working on, but I’m not quite done with it so there may be more issues to discus.
Until then,
Tom