Jun 04, 2013

One of the questions I get asked frequently by developers who visit Yellloh is about how we achieve the beautiful fade-in effect on our images. With design and ease of use being a central focus I wanted to make sure that images fade in gracefully and in a reliable manner with cross browser support. In developing a solution I didn’t want to use external scripts and wanted to keep the solution as small and efficient as possible.

The Ideal Outcome

With any page load I wanted each image to fade in as soon as it had finished loading, independent of any other event occurring on the page. This produces the beautiful effect where images fade in independent of each other. The solution I was looking for also had to be compatible with dynamic elements as we are using infinite scroll to add new elements to the DOM and have cross-browser compatibility.

The Problem

There are multiple problems to contend with when processing image states in the browser.

One issue is that there are multiple states the image can be in when the script processes it. The image may have already loaded before being processed, be in the process of loading, or not have started at all. Each state requires a different course of action.

Another issue is that any load event you bind to images pulled from the cache will not trigger.

Solution

The solution involves a function 9 lines long.

It works by iterating through each selector and deciding which of the two bits of code it will run on this selector. Line two of the function ensures this iteration through each element and returns the result to allow chaining.

The magic is in the IF statement that follows, which executes based on two possibilities:

  1. The image has already loaded (complete!)
  2. The image hasn’t finished loading (incomplete)

If it has loaded it executes the code immediately on the element.

If it hasn’t yet completed loading it will bind the load function to the element, waiting until it has finished loading before executing the code.

jQuery.fn.loadComplete = function (fn) {
    return this.each(function () {
        if (this.complete || this.readyState == 'complete') {
            fn.call(this);
        } else {
            $(this).load(fn);
        }
    });
};

Implementation

The only thing that remains is to execute this function on a desired selector and get it to fade in.

$('img').loadComplete(function(){
    $(this).fadeIn(800);
});

Bear in mind that to be able to fade in an image it must first be hidden. Hide the images you are going to fade in by default.

Conclusion

Based on this solution, every image is processed individually. If it has already loaded, it will fade in right away. If it hasn’t, the load function will bind and ensure that when the image has finished loading it will fade in independent of any other images.

The result is the beautiful effect where images fade in when they are ready for viewing.

You can see a working example of this at Yellloh.com.