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. Remy On 20th May 2008 at 18:05

    @Ana - regarding degrading there’s several ways. First off, it’s highly unlikely that the image would be loaded once the page has finished loading. If that were the case, then the non JS version should have the large image tag in a noscript tag.

    Assuming that the image loading is triggered by a link being clicked, the simple solution is that the target of the link is the actual full sized image.

    I hope that helps.

  2. coyr On 21st May 2008 at 14:05

    Thanks. You show it very easy ^_^

  3. Josh On 8th August 2008 at 10:08

    Hello, I try to load image with load function, image is in some other page.

    $(”#loader”).load(’img.php?img=6′);

    It works when I open img.php?img=6 but it won’t work load() function.

    I need really help, thank you.

  4. bart On 18th August 2008 at 18:08

    how can I make the image which has faded in a link?

  5. louis On 25th August 2008 at 02:08

    @ana - leave the “loading” class out of your html, then make the first step of your javascript to add the loading class, and carry on with the rest of the script. users without javascript therefore will not see the loading background image.

  6. Rob On 5th September 2008 at 08:09

    Excellent tutorial!

    It would be nice if this degraded gracefully for those with JavaScript disabled however.

  7. motan On 6th September 2008 at 22:09

    hello i was looking for something like this but i want to load content instead of an image can please put an example

    thanks

  8. bali web design On 8th September 2008 at 06:09

    to use this in mass image i think not too difficult, codes below will work.

    $("match_element_rule").each(function(index,el){ 
            var img = new Image();
            $(img).load(function () {
                    $(this).css('display','none');
                    $(el).removeClass('loading').append(this);
                    $(this).fadeIn();
            }).error(function () {
            // error handling
            }).attr('src', 'source_image');
    }); 

    i’ll try to create real example and post it

  9. kab On 8th September 2008 at 14:09

    I followed your tutorial - nice - and got it to work.

    Now, per your suggestion, I am trying an ajax call to create an imagemap.

    But I can’t figure out how to “bind” the cluetip plugin to the imagemap?

    I’ve tried “bubbling” but not really sure what its about. Livequery also I’m not quite getting.- Any hints?

    It comes up as an image map cause the cursor changes over the hotspot. But it has to be bound to cluetip after the ajax call - and not sure how to do that. Thanks

    $(document).ready(function(){
          $.cluetip.setup({insertionElement: '#loader'});
          $('area.load-local').cluetip({local:true, hideLocal: false, sticky: false});
    
          $('body').click(function(event) {
           if ($(event.target).is('a'))
              loadImage();
              return false;
          });
    });
    
    
    function loadImage() {
      var img = new Image();
      var imagemap=''+
                            '';                
      $(img).load(function () {    
            $(img).hide();
            $.ajax({
                url: 'tmp/Map_306.map',
                dataType: 'html',
                success: function (html) {
                  $('#loader').removeClass('loading').append(img)
                  //.append(html)
                  .append(imagemap);
                  $(img).fadeIn('slow');
                }
            });
          }).attr('src', 'getData.php?graphType=line')
            .attr('usemap', '#Map')
            .addClass('map')
        }
    
    <style>
    

    div#loader.loading { border: 1px solid #ccc; width: 200px; height: 200px; background: url(indicator.gif) no-repeat center center; } TEST View Graph

    Legend testing cluetip

  10. bali web design On 9th September 2008 at 01:09

    Ok i have finished to create real example using this script with multiple load images, and sequencing order

    take a look at http://www.chazzuka.com/blog/?p=240, hope it helps

  11. JohnnyO On 24th September 2008 at 05:09

    How would you modify this to delay / load an entire with multiple images etc…

  12. JohnnyO On 24th September 2008 at 05:09

    Sorry wordpress parsed my previous comment…

    How would you modify this to delay / load an entire div with multiple images etc…

  13. Josh On 30th September 2008 at 14:09

    I was wondering how I could use this script if I am using a CMS in which the images exist in the database and are dynamically called into the page with php?

    Am I mistaken in that this example would require the javascript file to be updated with new src image paths to load in new images?

    I’d like to have the ability to have a conditional loop with in my php templates that call in the images…is this possible with the script?

    What would I need to research?

    Thanks

    J

  14. Luigi On 4th October 2008 at 23:10

    I tried to modify this tutorial in order to have an image loaded after a select option, while subsequent changes on the select should replace the image with new ones. Also, I tried to post my effort to the split new Remy project, at this url: http://jsbin.com/eqimu But I seem not to find the way to let it run the way it should. Does anybody (more computer savy than I am) has an idea of how to properly approach the matter, please? Most probably, there is a better way to deal with such an issue…

  15. Ann P On 21st October 2008 at 06:10

    You are making an awesome work thanks to the simplicity of the “instructions” and because of you don’t short or jump any step assuming it is “well know” by a developer… I am not a developer, just a designer, so thanks a lot for not jumping any step and keeping it clear! ;)

    Ann Paul Prominentlabs Technology Solutions and Services

  16. adam On 23rd November 2008 at 01:11

    Joseph- if you want to check for many images in different divs, you can probably use the jquery onImageLoad plugin in combination with the this code.

    Tom Deater- This plugin also correctly handles image cache problems

    Check it out at: http://includes.cirkuit.net/js/jquery/plugins/onImagesLoad/1.1/documentation/

  17. Brian On 23rd November 2008 at 22:11

    My testing isn’t 100% complete but I did find that I got inconsistent results trying to retrieve image width and height using jQuery’s .width() and .height() methods from within the image onload event. Seems to work fine if I just access .width and .height from the non-jQueryified image object. Example:

    bad: $(img).load(function() { var mywidth = $(this).width(); var myheight = $(this).height(); }).attr(’src’, ‘images/foo.png’);

    good:

    $(img).load(function() { var mywidth = this.width; var myheight = this.height; }).attr(’src’, ‘images/foo.png’);

  18. michal On 28th November 2008 at 14:11

    hi. I want to use your script as background-image loader. I modified it but am thinking if this is indeed working. what i mean is on load of the image I change background-image of the div using jquery .css(). the only thing I wonder about is that if I load an image and then set fill background with it - will the browswer use loaded image from cache, or does it download it once more? any ideas? below my modified script:

    $(function () {
      var img = new Image();
      $(img).load(function () {
        $('#photos').removeClass('loading');
        $('#photos').css('background-repeat','no-repeat');
        $('#photos').css('background-position','center');
        $('#photos').css('background-image','img/photos_2.jpg');
      }).error(function () {
        // notify the user that the image could not be loaded
      }).attr('src', 'img/photos_2.jpg');
    });
  19. 3esmile On 2nd December 2008 at 09:12

    Is there a way to show non-image content in the or something like that? I really want that way to show my non-image content on my site. Thanks in advanced :D

  20. xanghe On 8th December 2008 at 06:12

    Thanks! Great tutorial (I know I’m parroting what everyone else said, but it’s true!)

  21. Thai Food Calories On 1st January 2009 at 12:01

    I was wondering how I could use this script if I am using a CMS in which the images exist in the database and are dynamically called into the page with php?

  22. Rich Paul On 18th January 2009 at 23:01

    For all those wondering about degradability, you could put in a default image that the browser will load. Then, using a script block toward the bottom of the page, you give that image the css display: none which will take care of the browser loading it from cache. Then, use the ready function to set up your image and load it in. Finally, use replaceWith to stick your new image in place of the default image and fade it in.

    Works really well and degrades nicely for those with Javascript turned off.

  23. Aaron On 23rd January 2009 at 16:01

    Great script!

    I want to load a bunch of images in a div but am having a hard time getting it to work.

    Some images might be inline with text.

    Is there a way to have it load all .img in a div with a class or id and add the loading icon dynamically so it does not matter what or how many images or their names it loads them and fades them in.

    Or if i could just fade in all images as they load that would be great too!

    Thanks for your help and i am new to jquery so any code examples that i could follow would be greatly appreciated. :)

    Thanks, Aaron

  24. Macgarment On 6th February 2009 at 08:02

    Hey everyone I have implemented the the script to an a tag which works great but the image loads every time I click can anyone point me in the right direction to kill the script after the images have loaded?

  25. wAtda On 23rd February 2009 at 23:02

    Macgarment,

       I think that you missed to enclose to your image loading function the "$();" or the "$(document).ready();" statements. Because codes within these statements will only occur at DOM loading. That should solve your problem, i hope.
    

    cheers!

Leave your own comment
  • http://