Welcome to my corner of the web. Here you'll find my ramblings about faith, church, drupal, Geeks and God (my podcast), and my other unrelated interests.

While you can subscribe to all posts here from the Subscribe link on the right, there are two other main feeds. There is the drupal and other technology feed along with the faith and church feed.

Preloading Images with jQuery

Posted on: Thu, 2007-02-01 09:45 | By: matt | In:

Update: This solution has been updated to a better solution that is explained in detail.

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.

Comments

#1 thanks!

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

#2 Thanks

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

#3 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 :)

#4 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.

#5 Thanks. Now I can use this

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

#6 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)

#7 Thank you.

Thanks, looks like it works just fine.

#8 Anyone got it working on IE?

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

#9 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.

#10 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.

#11 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.

#12 Awesome

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

#13 Great preloader!

Ditto to jettisoning the DW rubbish. Thank you Matt!

#14 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!

#15 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]);
	}
}

#16 Erroneous while condition

Hi there, you've made some nice improvements to the original snippet. However, your while condition is off. Instead of 'i > 0', you need 'i > -1'. Otherwise, the first image in the list will never be pre-loaded.

Otherwise, nice work! (to you, the OP, and everyone! :) )
-Rich

#17 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);
});

#18 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..

#19 Thanks

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

#20 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 ('');
});
}

#21 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 + '" />');
	});
}

#22 thanks

very thanks for examples

#23 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

#24 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

#25 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;
}

#26 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. }

#27 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);
});

#28 That's great improvement

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

#29 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;
}

}

#30 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

#31 Great comments

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

Thank you all.

#32 Thanks

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

#33 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!

#34 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.

#35 Use jQuery user interface locker plugin

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

PS. Thanks for an article.

#36 Preloading images in a crossfader

Hi,

I am a total newb here.. I just managed to get this working with a couple of wordpress posts, but I cant seem to get the preloading to work.

This is my script:

jQuery(document).ready(function(){
 
var cf = new Crossfader( new Array(
<?php
foreach ($div_ids as $id) {
$stringlist[] = "'cf".$id."'";
}
echo implode (',',$stringlist);
?>
), 1000, 5000 );
 
});

How can I preload this with a small preloading anim ?

#37 FYI, it is way more efficient

FYI, it is way more efficient to use:

new Image(arguments[i])

instead of
$("<img>").attr("src", arguments[i]);

There is a 20 second difference between the two methods if I have a list of 10000 images.

#38 Preload with slideshow

Thanks for the cool Ideas. But I can't realy get them up and running.
I used the code fro, #27 Last Time and I wanted to include a slideshow with a fade. But the images will not load as a preloader.
Can anyone help me?

$(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);
});

function slideSwitch() {
var $active = $('#slideshow IMG.active');

if ( $active.length == 0 ) $active = $('#slideshow IMG:last');

var $next = $active.next().length ? $active.next()
: $('#slideshow IMG:first');

$active.addClass('last-active');

$next.css({opacity: 0.0})
.addClass('active')
.animate({opacity: 1.0}, 1000, function() {
$active.removeClass('active last-active');
});
}

$(function() {
setInterval( "slideSwitch()", 5000 );
});

#39 valid html with document.createElement

I changed one line to:

jQuery(document.createElement("img")).attr("src", arguments[i]);

Using document.createElement is better when validating, if you use xhtml. The "" string causes validation errors.

#40 First time my example code

First time my example code did not show up. I'll try again.

The  "&lt;img&gt;" string causes validation errors because it's seen as markup.