Search

Image Loading

Posted on 4th February 2008 — Daniel Mee requested a tutorial and writes:

I have a large image (500k). I have a loading gif (little rotating circle thingy from ajaxload.info). I want the animated gif to be swapped with the large image once it’s loaded. The event may be on page load or may be some button onClick…

This is similar to how a LightBox would work, except Daniel wants complete control of the the load event.

This tutorial will show how to load images in the background, and once loaded handle the event and create your own response.

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:

  1. 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.
  2. Adding a styled div in our holder div, 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:

  1. Load the image in the background
  2. Hook a load event
  3. 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

Related posts

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>

Comments

  1. Amr On 3rd March 2009 at 02:03

    thanks for this great lesson, I learned how to load images as I in bad need for this but Actually I need to load it by click,

    could you please tell me how to create one function and to pass the image url via onClick event ?

    thanks in advance. Amr

  2. Amr On 3rd March 2009 at 02:03

    I created the onclick event, but with every click it add new instance, how can I remove these instances or prevent this duplication.

  3. Chris On 8th March 2009 at 18:03

    Just saying thanks for this post mate. Most appreciated. I turned the attributes into parameters to the Image being instantiated just for readability, but great to see something so concise. The video was an extra bonus. Nice one.

  4. j On 14th March 2009 at 04:03

    Thanks,,, very useful script… This has probably already been asked somewhere else in the comments, but is there anyway to call the image from the html rather than the script? cheers

  5. Rusty On 22nd March 2009 at 04:03

    finally I succeeded on multiple images, so the job you’ve done should be a good one. thanks a lot! still figuring out, how to get the imgs into links but I’m confidentliy expecting this to work soon … thanks again!

  6. Adam On 2nd April 2009 at 18:04

    Remy, For Remy or whoever might like to take it on, I would like to request an encore of this with a small modification. I think this is what many posters have been asking for- the scenario would be that images are already loaded into the DOM on the page, maybe pre-wrapped with the loading div (but maybe use JQ to add that markup), grab the SRC attrib. from each img element, detect loading complete, then fade it back in, rather than having the SRC be passed in with the script. Maybe Ill tinker with this and post when I get it working. Thanks! -Adam

  7. Adam On 2nd April 2009 at 20:04

    I did create a very simple version of this for images that pre-exist, and the script wraps the loader div around the images. This should work for those using a CMS.

    $(function () { $(’img.thumb’) .hide() .wrap(”") .load(function () { $(this).fadeIn(); $(’div.loading’).removeClass(’loading’); }).error(function () { // notify the user that the image could not be loaded }); });

  8. Andrew Roberts On 3rd April 2009 at 20:04

    Many thanks for your tutorial - fantastic.

    I have “lifted” the code into a slideshow project and am triggering images via onClick events. It works brilliantly until one returns to an image that was previously loaded. It seems to stick on hide().

    Any ideas? I’m sorry if I have misunderstood the concept of your tutorial, and i’m aiming to do something different!

    Thanks in advance,

    Andrew

  9. a3cube On 29th April 2009 at 23:04

    using this for multiple is so so simple…

    this is a reply to ‘bali web design’ method.

    create a div to hold ur thumbnails and set ‘a’ element with a ‘rel’ holding the img URL. ….an example will do it all

    < a rel=”http://imageurlgoes_here” >< / a >

    $(".imgholda a").each(function(index,el){ 
            var img = new Image();
            $(img).load(function () {
                    $(this).hide();
                    $(el).removeClass('loading').append(this);
                    $(this).fadeIn();
            }).error(function () {
            }).attr('src', $(this).attr('rel'));
    });

    this will easily load each image from the relative < a rel=”" > value.

  10. gorillapods On 2nd May 2009 at 13:05

    good article - Always wanted to know how they did that with jquery

  11. Michais Tzikas On 6th May 2009 at 13:05

    $(function () { $(”.click”).click(function(){ $(’#loader’).empty(); $(’#loader’).addClass(’loading’); var img = new Image(500,500); img.width = 500; img.height = 500; url = $(this).attr(”ref”); $(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’).empty().append(this); $(this).fadeIn(); }).error(function () { // notify the user that the image could not be loaded }).attr(’src’, url); }); });

    before append(this) i add empty() because if you have 2 different click events, on firefox it will add two images…

    also, i put Image(500,500) because i want the loading image to have diminsions 500×500 i also add img.width and height because chrome does not support new image dimensions

    url = $(this).attr(”ref”); (to take the image link)

  12. The Peach On 28th May 2009 at 13:05

    I can’t get this example to work correctly seems like the body of the load function isn’t working correctly

  13. Dave On 8th June 2009 at 06:06

    As usual, a great tutorial with your usual simplicity of explaining things! Thank You! It’s even better with the new J4D layout :)

  14. Alex On 15th June 2009 at 16:06

    How can we achieve this to load a large content from a function (not from another .html or .php page) instead of image? Is it possible?

  15. juliane On 18th June 2009 at 18:06

    how can i do this for every image on my blog?

    thanks in advance.

  16. Kaiserlino On 18th June 2009 at 22:06

    Hi… I would like to do such thing for many images in a post, not an individual one. On this page i have about 6 images. http://www.sneakersbr.com.br/editorial/1/NikeAirMax1-_Lanceiro

    Would like to apply the effect to the whole div, not every single image. It’s just to place the images inside the holder and change something?

    Thanks in advance :D

  17. Andrew Briggs On 27th June 2009 at 21:06

    Excellent tutorial, thanks! My only question was going to be “What about when javascript is disabled?” but I see you’ve already answered that!

  18. Gustav On 7th July 2009 at 00:07

    Hey!

    Can someone tell me how to load more than one image with this script? Thanks a lot!

  19. Geoffe On 8th July 2009 at 14:07

    And how if i had more images?

  20. marufsiddiqui On 15th July 2009 at 13:07

    Hi Remy, I was just trying this tutorial. Everything went well as you said except one thing. The delay function you showed is not working for me. I tried on my localhost. If I add the delay on $.ajax () function, i got response from sever something like page not found 404 error

    What can I do? Can you please reply?

  21. Eric ELZIERE On 5th August 2009 at 18:08

    Hi,

    I tried to apply what you sais above, but it does not seem to work with IE 7 (I guess it does not work neither with IE 8)…

    Here is the page: http://87.90.101.154/DesignAndCo/index.php?&Itemid=38&option=comvirtuemart&lang=fr&page=shop.productdetails&flypage=productflypagedesignandco&productid=372&categoryid=40&manufacturer_id=24&vmcchk=1

    Where you put your mouse over the small truck icon, it should popup a lightbox containing text and one or several images. Unfortunatly, the images are never displayed!

    Any idea? THanks in advance for your help!

    Cheers, EE.

  22. carey On 10th August 2009 at 03:08

    Or, you could just set the loader icon as a background to a div, or to the image, and it will be covered when the image loads.

  23. Adam Pflug On 12th August 2009 at 19:08

    Just thought I’d note that an easy way to achieve this same basic effect without javascript would be to set the spinner image as the background for the img tag you are loading. For example, for all images on a page you could just do: img { background: url(’images/loading.gif’) 50% 50% no-repeat; }

  24. James On 4th September 2009 at 14:09

    Hi there,

    Anyone know how I would do this for a background image to the body tag please?

    Thanks, James

  25. Vladimir On 6th September 2009 at 13:09

    You can just add CSS to your IMG width {background:url(spinner.gif) 50% 50% no-repeat;}

Leave your own comment
  • http://