Free Saeed Malekpour, Website Developer

Contact Me

@zoltandulac

Most Popular Posts

  • Cross Browser CSS Transforms – even in IE
  • How to Detect Font-Smoothing Using JavaScript
  • @font-face in Depth
  • Cross Browser HTML5 Drag and Drop
  • Installing Cygwin and FontForge for Windows
  • Cross Browser HTML5 Progress Bars In Depth
  • Creating Cross Browser HTML5 Forms Now, Using modernizr, webforms2 and html5Forms
  • Categories

    Caching Images With JavaScript and HTML5 progress Bars

    January 16th, 2012 by zoltan · 5 Comments

    Progress Bars can be used to show users how long it will be until a high-traffic page, like a photo gallery, fully loads. Click on the image to see one in action. (Photos courtesy of Do Not Forsake Me Oh My Darling)

    In my last article, , I discussed how to create progress bars and how to do fancy-pants CSS styling on them in all browsers. Sure, it’s cool eye candy, but where would you use one? I’m sure you have seen Flash sites that have a progress bars before (or what some of my designer friends call a “loader”), but just in case, take a look at the Star Trek Movie site to see an example of one in the wild. This loader tells the user how long it will take for the page to load and display. If this page takes a long time to load, a loader will prevent users from thinking the page is not loading properly and go someplace else. In most cases, these loaders show the percentage of assets have been loaded, and when it reaches 100%, the content is displayed. This prevents images from appearing half loaded when the content is first shown. While I wouldn’t want loaders for most HTML-based web sites, there are definitely times you would to want to do this, like when creating a full-screen slideshow. This article will show you how to make one easily.


    A Really Cool Photo Gallery Example of Image Caching With HTML5 <progress>

    Caching Images.

    Before we do anything, we need to know how to cache images. Developers have been using the DOM Level 0 Image() object to cache images since almost the beginning of JavaScript’s history. Basically it involves creating a new Image() object, and then setting the src to be URL of the image.

    var im = new Image();
    im.src = "http://www.useragentman.com/images/zoltFront.jpg";
    

    Back in the 1990′s, this technique was used a lot to cache images involved in animation of hover states. A good example of this is on the old Netcom Canada website circa 1997 (available today thanks to the magic of The Way Back Machine). If you mouseover any of the navigation links in the header, you’ll see the image button change in appearance. In order for this animation to happen as soon as the user hovers over the links, the page must cache all the hover-state images, so that the user doesn’t see any flicker on-hover as the image is loading. Modern developers would use CSS sprites to do this, but back in the day, this was the only way to go.

    But how can one use this technique to update a progress bar? The Image() object has a load event, so we can use that to increment a progress bar. To simplify this process, I have created a very simple JavaScript library, imageCache.js, that will cache an array of image URLs and fire off two events: one when each image is loaded, and one where the whole array is loaded. Image caching is as simple as this:

    var s=["images/1.jpg", "images/2.jpg", "images/3.jpg"];
    imageCache.pushArray(s, loadImageEvent, loadAllEvent);
    

    loadImageEvent is a callback that is called every time an image is loaded, and loadAllEvent is called when all of the images are loaded.

    Download imageCache.js from GitHub.

    Using <progress> to Show When Each Image Has Loaded

    In the image gallery example at the beginning of this article, we have 28 images that we want to load into cache before showing the content of the page. We also want a progress bar to show these images loading. In order to do this, we need to make two containers: one that holds the progress bar and one that holds the content:

    <-- The Progress Bar Container -->
    <div id="progressContainer">
        Loading: <br />
        <progress id="loader" max="28" value="0">
           <strong>Loaded <span id="value">0</span>/28</strong>
        </progress>
    </div>
    
    <-- The Content Container -->
    <div id="content">
       <!-- this should contain the content for the rest of the site -->  
    </div>
    
    

    You would then create a JavaScript snippit that would pre-cache all the images. What follows is an example that uses jQuery to do this, but since the imageCache.js library itself doesn’t need jQuery, feel free to use any framework you like (or lack of framework if you are “Teh Hardcorez“):

    var dnfmomd = new function () {
       var me = this;
       
       var $loader,
           currentImage = 0;
       
       
       me.init = function () {
          
          var s = [];
          
          for (var i=1; i<=28; i++) {
             s.push('images/dnfmomd/' + i + '.jpg');
          }
          $loader = $('#loader');
          
          $loader.max = s.length;
          imageCache.pushArray(s, loadImageEvent, loadAllEvent);
          
       }
    
       function loadImageEvent() {
          val = parseInt($loader.attr('value'));
          val++;
          $loader.attr('value', val);
       }
       
       function loadAllEvent() {
          $('body').addClass('loaded');
          showImage(1, true);
       }
    
       ....
    
    }
    
    /*
     *  Use $(window).load() instead of $(document).ready() because we wan't to start caching images
     *  as soon as the progress bar images are loaded.
     */
    
    $(window).load(dnfmomd.init)
    

    Note that progress bar’s value is increased every time an image is loaded, and when all the images are loaded, we add the loaded class to the body. This will result in the progress bar disappearing and the content becoming visible, due to this CSS in the page:

      #content {
         display: none;
      }
    
      body.loaded #content {
         display: block;
      }
    
      body.loaded #progressContainer {
         display: none !important;
      }
    

    Can We Show Other Things Loading in the Progress Bar Besides Images?

    It is possible to show CSS and JavaScript in the progress bar using yepnope.js. It is a little bit more involved, but very doable (I have done it before), and I leave it as an exercise to the reader to do it. Post it below, and I’ll give you full geek-cred. If no one does it, I will probably take some time and publish an example in a few weeks, but I thought it would be neat to offer up a little challenge. :-)

    Tags: Uncategorized

    5 responses so far ↓
    • 1 Mathias Bynens // Jan 17, 2012 at 3:30 am

      If you used an <object> to preload stuff in non-IE browsers, you could probably make this work for other file types as well (e.g. CSS, JavaScript…).

    • 2 zoltan // Jan 17, 2012 at 7:27 am

      @Mathias: Thanks for the tip! The link you included suggests an alternative for IE as well… it should be trivial to refactor imageCache.js to handle all types of files.

    • 3 Tom // Jan 25, 2012 at 6:28 am

      Just what i´m looking for… i make my own loader, with a counter adding to every image an Onload common function, but that´s not work with the CSS background images… but i was using the $(document).ready() instead of $(window).load(). Thanks for share

    • 4 Svetlana // Mar 19, 2012 at 4:35 am

      Hi, guys! Thank you for a very useful article! We`ve just posted an article “How to Cache Images with HTML5″ on our blog: http://www.learncomputer.com/how-to-cache-images-with-html5/
      Migt be useful for your readers too.
      Thanks.

    • 5 Web Design Macclesfield // Apr 30, 2012 at 6:41 am

      Thanks for the information about pre loading images…

      In addition, to prevent caching in your browser, or indeed on the web server, some people amend a random number (or the time) to the end of the requested image url.

      This is usually the case on websites requesting images from a web cam.

      i.e.
      request ‘/images/camimage.jpg?113900′
      and then next time request ‘/images/camimage.jpg?114000′

    Give Feedback

    Don't be shy! Give feedback and join the discussion.

    Please Note: If you are asking for help using the information on this page or if you are reporting a bug with the code featured here, please include a URL that shows the problem you are experiencing along with the browser/version number/operating system combination where the issue manifests itself. Without this information, I may not be able to respond.

    An orange star denotes a required field.