Basic Version
In our basic version, we will have a single div containing a loading spinner and once our large image is loaded (in the background) we will remove the spinner and insert our image.
There’s a few ways to approach the loading screen, two of which are:
- Use a background image on the holder
div, this way we can easily centre align horizontally and vertically using CSS, rather than adding extra markup. - Adding a styled
divin our holderdiv, then remove the entire block of markup when the image loads.
I’ve provided a screencast explaining how to achieve this (though it is based on the CSS version, also shows how to do this with a separate loading div).
Watch the jQuery basic image load screencast (alternative flash version)
View the demo and source code used in the screencast
Note that in the demonstration as I am simulating loading a slow to load image by including a script tag at the bottom of the markup. In your real world version, you obviously would not include it.
HTML Markup
The markup (segment) that we’re using is extremely simple. Note, however, I’ve included a ‘loading’ class on the div. This will be manipulated in our jQuery once the image has loaded behind the scenes:
<div id="loader" class="loading"></div>
CSS
For the demo, I’ve set the height and width of the empty div, but also included a background image which indicates something is loading.
You can use any kind of image - I’ve seen applications use much larger animated gifs to simulate a loading message box.
DIV#loader {
border: 1px solid #ccc;
width: 500px;
height: 500px;
}
/**
* While we're having the loading class set.
* Removig it, will remove the loading message
*/
DIV#loader.loading {
background: url(images/spinner.gif) no-repeat center center;
}
jQuery
The jQuery’s job is to:
- Load the image in the background
- Hook a load event
- Once the image has loaded, strip the loading class and insert the image
// when the DOM is ready
$(function () {
var img = new Image();
// wrap our new image in jQuery, then:
$(img)
// once the image has loaded, execute this code
.load(function () {
// set the image hidden by default
$(this).hide();
// with the holding div #loader, apply:
$('#loader')
// remove the loading class (so no background spinner),
.removeClass('loading')
// then insert our image
.append(this);
// fade our image in to create a nice effect
$(this).fadeIn();
})
// if there was an error loading the image, react accordingly
.error(function () {
// notify the user that the image could not be loaded
})
// *finally*, set the src attribute of the new image to our image
.attr('src', 'images/headshot.jpg');
});
Added Functionality
The jQuery code used is the constructs of our load function. If we wanted to style the image in any way, add classes or run an Ajax request before showing the image, it would go inside the .load() function.
This functionality could also be placed inside of a .click() event handler or anything else if you wanted to trigger the image loading.
For example, if you had a particular image map linked to this image that you wanted to request via Ajax the contents of the load function would be this:
$(img)
.load(function () {
$(this).hide();
// our bespoke ajax hit that's required with the image
// it will return the HTML for the <map> element and
// linked <area> element.
$.ajax({
url: 'image-map.php',
data: 'img=' + i.src, // the image url links up in our fake database
dataType: 'html',
success: function (html) {
// because we're inside of the success function, we must refer
// to the image as 'img' (defined originally), rather than 'this'
$('#loader')
.removeClass('loading')
.append(img)
.append(html);
// now show the image
$(img).fadeIn();
}
});
})
// code continues as before
You should follow me on Twitter here I tweet about jQuery amongst the usual tweet-splurges!
Related screencasts
Demo
If you find this demo doesn't work as expected, it's possibly due to the demo running from within an iframe. Try running the demo in it's own window.
Source Code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>Image Loading</title>
<style type="text/css" media="screen">
<!--
BODY { margin: 10px; padding: 0; font: 1em "Trebuchet MS", verdana, arial, sans-serif; font-size: 100%; }
H1 { margin-bottom: 2px; }
DIV#loader {
border: 1px solid #ccc;
width: 500px;
height: 500px;
overflow: hidden;
}
DIV#loader.loading {
background: url(/images/spinner.gif) no-repeat center center;
}
-->
</style>
<script src="/js/jquery.js" type="text/javascript"></script>
<script type="text/javascript">
<!--
$(function () {
var img = new Image();
$(img).load(function () {
//$(this).css('display', 'none'); // .hide() doesn't work in Safari when the element isn't on the DOM already
$(this).hide();
$('#loader').removeClass('loading').append(this);
$(this).fadeIn();
}).error(function () {
// notify the user that the image could not be loaded
}).attr('src', 'http://farm3.static.flickr.com/2405/2238919394_4c9b5aa921_o.jpg');
});
//-->
</script>
</head>
<body id="page">
<h1>Image Loading</h1>
<p>This demonstration shows how to pre-load an image in the background while showing a loading screen. It also supports loading the image, then running additional code, such as Ajax requests before finally showing the image.</p>
<p><a href="http://jqueryfordesigners.com/image-loading/">Read the article this demonstration relates to</a></p>
<div id="loader" class="loading">
</div>
<p><a href="http://www.flickr.com/photos/remysharp/">More photos...</a></p>
<!-- this is just a way to simulate a delay (the script will sleep for 2 seconds then response) -->
<script src="image-load-demo.php?action=delay" type="text/javascript" charset="utf-8"></script>
</body>
</html>


Scott Mackenzie On 18th September 2009 at 08:09
Thanks for this! Easy to follow. Simple to execute.
HappyPod On 13th October 2009 at 22:10
Related to this topic — I have a page that:
The page can be found at http://test.happypod.com/preloadimage/
The part that I don’t quite understand is that when I inspect the page using Firebug (Net tab):
Why does the browser fetch signup_ro.png again although that image has been preloaded? For screenshot, see: http://test.happypod.com/preloadimage/firebug.png
David On 2nd November 2009 at 22:11
Hi,
thank you for this great tutorial. Could you just tell us how to stop the loading? Because I have to override the loading, and I can’t stop the first load. So my complete callback are called 2 times and not 1….
thank you for your help!
Kevin On 26th November 2009 at 22:11
Hey - thanks for this post! I kept thinking, “isn’t load only for AJAX?” and thought I was going to have to do up a whole AJAX handler in my PHP script just to swap images on the fly (I would just return the proper DOM element and swap it in…) - but this saved me the time and worked like a charm.
I hear that swapping images is territory to tread lightly when it comes to Webkit browsers, but I’ll cross that bridge when I come to it…it’s good for now :D
Take care.
Mike On 2nd December 2009 at 03:12
Excellent! Solved the exact problem I was having. Thanks for posting this!
Benedict Raynes On 7th December 2009 at 18:12
This is strange - this method works very well on a apache server located on my computer, but when I tried deploying a website written with this code on any hosting, outside server - the images either didn’t show up at all or showed up severely distorted. Do you know what could be wrong?
estevan On 18th January 2010 at 09:01
Any suggestions on how I can implement this code without designating the image src in the javascript? I’m trying to set something up like this in Wordpress and I want it load the img from the PHP.
Kyle On 18th January 2010 at 13:01
Hi,
First and foremost this is a great piece of work you have provided us with, thanks very much.
I was wondering if you could or someone could help me with one problem Im having, I cant get the image fade to work on this page http://kylehouston.com/new/index_new.html everything else works fine.
Thanks in advance
Kyle
Kevin Crawford On 1st March 2010 at 14:03
Would it be possible to include the tag in the original markup, hide it initially with CSS or javascript (and thus displaying the spinner BG behind it instead), and fade it in once it has loaded, using load()? That way you wouldn’t have to define the “src” attribute in the javascript, and it would make it unobtrusive.
Although, I suppose for some more advanced applications of this concept, the src would need to be originate dynamically from the javascript anyways =D
Kevin Crawford On 1st March 2010 at 15:03
Sorry for the double-post, but after the same request from Estevan I decided to tackle it myself!
<div id="loader" class="loading"&rt; <img src="image.gif" /&rt; </div&rt; $(function() { $('#loader img').hide().load(function() { $('#loader').removeClass('loading'); $(this).fadeIn(); }); // This makes it work, even when the image is cached var src = $('#loader img').attr('src'); // Stores original src from HTML as a variable $('#loader img').attr('src', '') // Set's source to empty string $('#loader img').attr('src', src) // Sets it back to the old value // BELOW IS AN ALTERNATIVE WAY TO MAKE IT WORK FOR CACHED IMAGES $('#loader img').hide(); $(window).load( function() { $('#loader').removeClass('loading'); $('#loader img').fadeIn('slow'); }); });I only tested the two solutions in FireFox, so I’m not entirely sure how well it will work cross-browser. Hope it helps someone.
Ben Lacey On 27th March 2010 at 02:03
Very nice article, I follow your JQuery iPod podcasts and I’m always very impressed with the stuff you put together.
I find JQuery to be really lightweight and a very useful framework for JavaScript awesomeness. Keep up the good work!
Ben Lacey (Lacey Tech Solutions)
DJ Vermeulen On 2nd April 2010 at 14:04
Thanx. The tutorial worked great on my images, but i’ve got a flash (.swf) file that needs to load as well. This script doesn’t seem to work on that or how must the code be changed to accommoodate a loading flash file.