Skip to content

Instantly share code, notes, and snippets.

@paulirish
Created January 4, 2010 02:38
Show Gist options
  • Save paulirish/268257 to your computer and use it in GitHub Desktop.
Save paulirish/268257 to your computer and use it in GitHub Desktop.
imagesLoaded() jquery plugin
// $('img.photo',this).imagesLoaded(myFunction)
// execute a callback when all images have loaded.
// needed because .load() doesn't work on cached images
// mit license. paul irish. 2010.
// webkit fix from Oren Solomianik. thx!
// callback function is passed the last image to load
// as an argument, and the collection as `this`
$.fn.imagesLoaded = function(callback){
var elems = this.filter('img'),
len = elems.length,
blank = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
elems.bind('load.imgloaded',function(){
if (--len <= 0 && this.src !== blank){
elems.unbind('load.imgloaded');
callback.call(elems,this);
}
}).each(function(){
// cached images don't fire load sometimes, so we reset src.
if (this.complete || this.complete === undefined){
var src = this.src;
// webkit hack from http://groups.google.com/group/jquery-dev/browse_thread/thread/eee6ab7b2da50e1f
// data uri bypasses webkit log warning (thx doug jones)
this.src = blank;
this.src = src;
}
});
return this;
};
@ksykulev
Copy link

You should probably unbind the load event when the image is loaded (line 17).
...
elems.bind('load',function(){
$(this).unbind('load');
if (--len <= 0 && this.src !== blank){ callback.call(elems,this); }
}
...
I abuse this script by replacing the src for some images multiple times, which binds the load event multiple times. This in turn causes the callback to be called many times on subsequent calls to imagesLoaded, since the old load events have 'len' set to zero on completion.

@ksykulev
Copy link

Here's my revised version.. https://gist.github.com/1170048
Line 18 has the notable change.

@cjboco
Copy link

cjboco commented Aug 25, 2011

@ksykulev - Just a quick thought, would this cancel the load event on the real image, since this would unbind the load event when setting the blank image? Haven't tested it yet, just curious.

@ksykulev
Copy link

@cjboco - hmmm good point, i didn't think about that..
In my particular case I have a gallery of images, and i give the user the ability to switch between the small or large res. images. I need to rescale some of elements around the images, so I use this script to let me know when all the images are loaded.
It appears to work OK in webkit... but some more thorough testing is definitely needed.

Not sure if this helps, but I also namespaced the binded load event like this:
elems.bind('load.imagesLoaded',function(){
$(this).unbind('load.imagesLoaded');
if (--len <= 0 && this.src !== blank){ callback.call(elems,this); }
}

@ksykulev
Copy link

Yes that does break it in webkit, scratch that
Only way around that is to break the cache:
src + ?_="+(new Date().getTime())
:(
Thanks for pointing that out.

Could the unbinding happen inside the callback after all the images have loaded?
elems.bind('load.imagesLoaded',function(){
if (--len <= 0 && this.src !== blank){ elems.unbind('load.imagesLoaded'); callback.call(elems,this); }
}

@cjboco
Copy link

cjboco commented Aug 25, 2011

@ksykulev - maybe add it after "this.src = src"?

@ksykulev
Copy link

@cjboco - After some testing:
Putting the unbind after the "this.src = src" unbinds the load event too fast and it doesn't get called..
Putting the unbind in the conditional seems to be working OK.

elems.bind('load.imagesLoaded',function(){
if (--len <= 0 && this.src !== blank){ elems.unbind('load.imagesLoaded'); callback.call(elems,this); }
}

@cjboco - Thanks for your help!

@paulirish
Copy link
Author

hey guys

mr @desandro has picked up this script and given it a proper repo as a home:

https://github.com/desandro/imagesloaded

I've added the namespaced events to my gist above as that seems like a good idea. but in general, david's version is the new canonical one

@StephanFischer
Copy link

ok, its a cached images solution for webkit? but its simpler by checking width or height after loading event:

    img.addEventListener("load", function() 
    {
      var tmrLoaded = window.setInterval(function()
      {
        if (img.width) 
        {
          window.clearInterval(tmrLoaded);  
          alert( "its done!");
        }
      }, 100);

    }, false);

Greetz

@ahoward
Copy link

ahoward commented Feb 10, 2013

nice! i'm using this here -> https://github.com/ahoward/jquery.bires

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment