Image Fade In with jQuery (UPDATED)

I often find it a much nicer effect to have images fade in when they’ve finished loading, opposed to watching them build on screen. This is super easy to do with a bit of jQuery and CSS, but I’ve always had an issue that I only today discovered a work around for.

Imagine you have a gallery with 10 images all loading for the first time together. I’ve used a unordered list in this example, but you could use whatever markup you wanted for your own gallery.

<ul id="gallery">
 <li><img src="image_1.png" alt="" /></li>
 <li><img src="image_2.png" alt="" /></li>
 <li><img src="image_3.png" alt="" /></li>
 <li><img src="image_4.png" alt="" /></li>
 <li><img src="image_5.png" alt="" /></li>
...
</ul>

Having created our list of images, lets put some simple CSS in place to give the appearance of loading. To do this we set the images to visibility to hidden and the list items’s background to an ajax loading gif.

#gallery li { background: url('loading.gif') no-repeat center center; }
#gallery li image { visibility: hidden; }

Finally we need some jQuery to fade the images in once they’ve finished loading. I will start with the jQuery I have always used and then discuss its problems and a solution.

jQuery("#gallery img").load(function() {
	jQuery(this).css("opacity", 0).css("visibility", "visible").animate({opacity: '1'}, 'fast');
});

The problem with the above method is caching. Most modern browsers will make an effort to cache images and large files. When you first load this page this will all work perfectly. The browser will begin loading images for the DOM and in the mean time your script will have been initialized and jQuery will be watching for your images to complete loading. The problem is that the second time you load this page most of those images will now will be cached by the browser. Your browser will load your images long before your script is even called. Your script will essentially sit forever waiting for a call to say the images have finished loading, but never receive one. The solution is to include an .each() function to the .load(). This each can check if an image is already complete and if so just manually call .load().

jQuery("#gallery img").one('load', function() {
    jQuery(this).css("opacity", 0).css("visibility", "visible").animate({opacity: '1'}, 'fast');
}).each(function() {
    if(this.complete) {
        jQuery(this).load();
    }
});

UPDATE:

I previously didn’t have the “jQuery(this).load();” wrapped in braces, which seems to cause problems in IE. This seemed to fix it however on my path to solve the IE problem I came to a point where I could no longer create it.