Matt Farina - Tech / Faith / Life

Preloading Images with jQuery

In

Update: There is an updated version of this post that goes beyond basic image preloading on InnovatingTomorrow.net

Creating cool effects on a website with jQuery is fun and can definitely add to the coolness factor of a site. But, if the script is replacing an image and you have a time gap while you wait for that image to load (remember there are those still on dial-up and big images can take a couple seconds to load on broadband) the effect went from cool to unprofessional.

The solution is to preload the images so they display when you want them to. This is pretty simple with jQuery.

First, you need the plug-in code for jQuery to do the image preloading. The fairly short code is:

jQuery.preloadImages = function()
{
  for(var i = 0; i<arguments.length; i++)
  {
    jQuery("<img>").attr("src", arguments[i]);
  }
}

You can insert this code in a separate javascript file and load it before you do any of your lifting or, as I did for Geeks and God, you can throw it at the top of your javascript file where you are doing your effects.

After including this script you need to tell it what images to preload. To do this the code is simply:

$.preloadImages("image1.gif", "/path/to/image2.png",
"some/image3.jpg");

This will run when the document is ready to accept javascript (just like using .ready() but shorter). Just load the function up with comma separated images.

thanks!

Hey just wanted to thank you for posting this -- now I can jettison the crappy old preloader I have been borrowing from Dreamweaver...

Thanks

I used this as well. Thank you, clean and simple.

Nice Shot!

hello Matt,

great mixture of Jquery. I am using both Prototype and Jquery due to some reasons and was thinking to use prototype for image pre-loading. I am happy that you solved my problem using Jquery, Thanks for it :)

Image preloader detailed explanation

Hi and thanks for this post. I came to this page through google.

I also found this article on preloading images with jQuery that describes the proccess in more detail. It's a good article for jQuery newbies.

Thanks. Now I can use this

Thanks. Now I can use this on my new Nerds and Satan Website!

Thanks, small and simple

That worked like a charm,
Opera does not preload images that are in img tags which are hidden (dispaly:none) thus a preloading is needed (often times)

Thank you.

Thanks, looks like it works just fine.

Anyone got it working on IE?

Doesn't seem to work on IE (neither 6 nor 7). Anyone has it working on IE?

Yeah

I've used this in IE for some time. Since the jQuery 1.0.4 days. I've seen it work in IE6 and IE7 on multiple sites. The must be something else going on here.

You're supposed to use self

You're supposed to use self closing tags with jQuery, not doing it can lead to weird troubles. I mean instead of .
But even with this properly handled, it seems ie6 doesn't preload.

You're supposed to use self

You're supposed to use self closing tags with jQuery, not doing it can lead to weird troubles. I mean <img/> instead of <img>.
But even with this properly handled, it seems ie6 doesn't preload.

Awesome

Just wanted to thank you for this, works like a charm !

Great preloader!

Ditto to jettisoning the DW rubbish. Thank you Matt!

Thanks

Thanks for this simple and clean solution Matt. I was looking for something to preload a status bar and this fit the bill.

Cheers!

Small change

Hi, this makes it little bit quicker and also a bit more flexible. You can pass on array or list of images to preload.

var prelod = ['image1.gif', 'image2.gif'];
$.preloadImages(preload);

$.preloadImages('image1.gif', 'image2.gif');


jQuery.preloadImages = function() {
var a = (typeof arguments[0] == 'object')? arguments[0] : arguments;
for(var i = a.length -1; i > 0; i--) {
jQuery("<img>").attr("src", a[i]);
}
}

You can also use the load()

You can also use the load() function if you need a callback:

var _images = ['image1.jpg','image2.jpg'];

$.each(_images,function(e) {
$(new Image()).load(function() {
alert($(this).attr('src') + 'has loaded!');
}).attr('src',this);
});

cumulative onLoad of all images

good idea.. I added a counter to ensure all said images were loaded before calling begin():

var _images = ["img1.jpg", "image2.jpg", "imij3.jpg"];
var gotime = _images.length;

$.each(_images,function(e) {
$(new Image()).load(function() {
if (--gotime < 1) begin();
}).attr('src',this);
});

Note: there's no error checking.. those images better exist or your begin() ain't gonna..

Thanks

Works good. This helped me with my interval problem :)

Rewrite

I couldn't get your version to work for some reason. FireBug did list the images in its net pane showing them downloading, but when I mouseovered the element I wanted to use the preloaded images on it just loaded them again. The following rewrite seems to work fine, don't ask me why though!

jQuery.preload = function()
{
jQuery.each (arguments,function (e)
{
jQuery ('');
});
}

Damn, the actual line that

Damn, the actual line that injects the images seems to have been censored! Lets try that again:

jQuery.preload = function()
{
jQuery.each (arguments,function (e)
{
jQuery ('<img src="' + this + '" />');
});
}

thanks

very thanks for examples

RE: - Preload images jQuery cycle issue

Here's how we got around the issue of preloading images:

We used setInterval to call a function iteratively every 1 second to check if all the images have loaded:

var vCycleImages = setInterval("setImgCycleStatus()", 1000);

$(function() {
$('#fadeCenter').cycle();
$('#fadeCenter').cycle('stop');
});

function setImgCycleStatus() {

if ($.preloadImages("pic1", "pic2", "pic3", "pic4")){
$('#fadeCenter').cycle({
speed: 500,
timeout: 8000,
delay: -5000,
startingSlide: 0
});
clearInterval(vCycleImages);
}
}

jQuery.preloadImages = function() {
var bImgLoaded = true;

for(var i = 0; i < arguments.length; i++){
if (document.getElementById(arguments[i]).complete == false) {
bImgLoaded = false;
}
}
return bImgLoaded;
}

Hope this helps.

Samir Pipalia
Pipalia Software House
http://www.pipalia.co.uk

Example

If anyone is looking for an example, for the previously mentioned solution, please visit our customer's site at http://www.cefinaDesign.co.uk

I ended up using a variation

I ended up using a variation of Samir's sample. Instead of listing out each id for the image though I used the selector of any image in the div#slideshow.

var vCycleImages = setInterval("setImgCycleStatus()", 1000);

function setImgCycleStatus() {
   if ($.preloadImages($("#slideshow img"))) {
      $('#slideshow').cycle({ delay: 1000, speed: 1000 });
      clearInterval(vCycleImages);
   }
}

jQuery.preloadImages = function() {
   var bImgLoaded = true;

   for (var i = 0; i < arguments.length; i++) {
      if (arguments[i].complete == false) {
         bImgLoaded = false;
      }
   }
   return bImgLoaded;
}

Slight Modification

I add to make a slight modification to my script for it to work correctly. See below on line 14.

1.  var vCycleImages = setInterval("setImgCycleStatus()", 1000);
2.
3.  function setImgCycleStatus() {
4.     if ($.preloadImages($('#slideshow img'))) {
5.        $('#slideshow').cycle({ delay: 1000, speed: 1000 });
6.        clearInterval(vCycleImages);
7.     }
8.  }
9.
10. jQuery.preloadImages = function() {
11.    var bImgLoaded = true;
12.
13.    for (var i = 0; i < arguments.length; i++) {
14.       if (arguments[i].attr("complete") == false) {
15.          bImgLoaded = false;
16.       }
17.    }
18.    return bImgLoaded;
19. }

Last Time

This is another variation of the above posts that I much prefer. It's all contained in one function and seems easier to follow.

$(document).ready(function() {
   vCycleImages = setInterval(function() {
      var bImgLoaded = true;
      var images = $("#slideshow img");

      for (var i = 0; i < images.length; i++) {
         var img = images[i];
         if (img.complete == false)
            bImgLoaded = false;
      }

      if (bImgLoaded) {
         $("#slideshow").cycle({ delay: 1000, speed: 1000 });
         clearInterval(vCycleImages);
      }
   }, 1000);
});

That's great improvement

That's great improvement over my code Deran - thanks for submitting your tip.

Where be the recursive event driven one?

real quick copy and paste from some code I wrote....no comments or explanations sorry

function loadImage()
{
if(loadGallery.DATA.length>0)
{
$(new Image()).load(function()
{
loadGallery.DATA.reverse().pop();
loadGallery.DATA.reverse();
console.log(loadGallery.DATA[0][9]);
loadImage();
}).attr('src','/Gallery' + loadGallery.DATA[0][9]);
}

else
{
return;
}

}

loading images, creating automatic array

This is excellent code...I am just wondering if i can upload images from a file (specified) and automatically creating an array based on a user click on link?

for example:

user clicks on link

jQuery compares the link and uploads images from link related file, creates array automatically based on a maximum number of images for display on a page that is #content based.

is this possible?

eyveneena

Great comments

Great topic and the comments are also cool with helpful code hints.

Thank you all.

Thanks

This snippet is both useful and clean, I never thought of writing it so simply. Thanks

Thanks for the post

Wow, I and my Google Notebook > Code Snippets > JavaScript thank you for this post! Quick and dirty, no verbose explanation, this was exactly what I was looking for. Thanks for posting this Matt, you saved me a ton of time just now and will in the future.

Thank you thank you!

What if the user start

What if the user start clicking around before the preloading has complete? Is there a way to block ui with some graphic indicator? Thanks.

Use jQuery user interface locker plugin

@Nemo, you can use jQuery uiLock plugin to block user interactions.

PS. Thanks for an article.