Grow your CSS skills. Land your dream job.

Last updated on:

Lazy Loading Images

Use a blank.gif as the src of images, and include the width and height of the final image.

<img src="blank.gif" class="lazy" data-src="/images/full-size.jpg" width="240" height="152">
/* lazyload.js (c) Lorenzo Giuliani
 * MIT License (http://www.opensource.org/licenses/mit-license.html)
 *
 * expects a list of:  
 * `<img src="blank.gif" data-src="my_image.png" width="600" height="400" class="lazy">`
 */

!function(window){
  var $q = function(q, res){
        if (document.querySelectorAll) {
          res = document.querySelectorAll(q);
        } else {
          var d=document
            , a=d.styleSheets[0] || d.createStyleSheet();
          a.addRule(q,'f:b');
          for(var l=d.all,b=0,c=[],f=l.length;b<f;b++)
            l[b].currentStyle.f && c.push(l[b]);

          a.removeRule(0);
          res = c;
        }
        return res;
      }
    , addEventListener = function(evt, fn){
        window.addEventListener
          ? this.addEventListener(evt, fn, false)
          : (window.attachEvent)
            ? this.attachEvent('on' + evt, fn)
            : this['on' + evt] = fn;
      }
    , _has = function(obj, key) {
        return Object.prototype.hasOwnProperty.call(obj, key);
      }
    ;

  function loadImage (el, fn) {
    var img = new Image()
      , src = el.getAttribute('data-src');
    img.onload = function() {
      if (!! el.parent)
        el.parent.replaceChild(img, el)
      else
        el.src = src;

      fn? fn() : null;
    }
    img.src = src;
  }

  function elementInViewport(el) {
    var rect = el.getBoundingClientRect()

    return (
       rect.top    >= 0
    && rect.left   >= 0
    && rect.top <= (window.innerHeight || document.documentElement.clientHeight)
    )
  }

    var images = new Array()
      , query = $q('img.lazy')
      , processScroll = function(){
          for (var i = 0; i < images.length; i++) {
            if (elementInViewport(images[i])) {
              loadImage(images[i], function () {
                images.splice(i, i);
              });
            }
          };
        }
      ;
    // Array.prototype.slice.call is not callable under our lovely IE8 
    for (var i = 0; i < query.length; i++) {
      images.push(query[i]);
    };

    processScroll();
    addEventListener('scroll',processScroll);

}(this);​

Reference URL

Comments

  1. Robin
    Permalink to comment#

    You got a demo?

  2. Robin
    Permalink to comment#

    My bad. Its not working on iPad, is it? Nothings happening on my iPad2.

    • Markus
      Permalink to comment#

      Same here on iPad 3 — nothing happens, no fallback to see, even with the last updated version Feb 23, 2014…

    • Matt
      Permalink to comment#

      To get this to work on iPad all you should need to do is change :

      addEventListener(‘scroll’,processScroll);

      to :

      addEventListener(‘touchmove’,processScroll);

  3. Permalink to comment#

    Chris, what happens to no-js users? It doesn’t sound like a good idea to do this… as you can see on iPad etc ;)

    • Robin
      Permalink to comment#

      @Anselm: iPad is not a no-js user. It’s a touch/mobile user (different scroll event perhaps?).

      I think we’ve long-passed the station where we should build fallbacks for non-js (standard) users. Especially regarding images.

    • Lorenzo Giuliani
      Permalink to comment#

      you can use a simple fallback in the markup:

      
      <noscript>
      <img src="my_image.png" width="600" height="400" class="lazy">
      </noscript>
      <img src="blank.gif" data-src="my_image.png" width="600" height="400" class="lazy">
      

      and in css using modernizr.js:

      
      .no-js .lazy {
      display:none;
      }
      
    • Anonymous
      Permalink to comment#

      @Robin you should always provide fallback for users without JavaScript support.

  4. I have been building a fast, stand alone & robust lazy loader.

    You’ll find it here : https://github.com/fasterize/lazyload

    Why not join forces ? :)

    There’s a lot of use cases that your lazyloader is not fixing, like onload-inviewport images (so no scroll event). Etc. (see test/)

    Was great reading your code and compare.

    Thank you

    • Lorenzo Giuliani
      Permalink to comment#

      I have seen your code a few days after i wrote this one featured on dailyjs, if I have patches I’ll send you a pull request.

      Here I have an updated Gist: 2171438, can’t remember what changed between the submitted version and the gist.

    • David
      Permalink to comment#

      Hi Vincent! Does this plugin work with background-image property instead of using tags? Thank you!

  5. this is not work full in my blog,,

    please help me please. . .

  6. I’m probably asking a dumb question, but… What would this be useful for? To make images load slower than they should? Why?

    Please, i’m not trying to be harsh, i just don’t get this.

    • Robin
      Permalink to comment#

      It’s to prevent unnecessary image loading and optimize bandwidth usage.

      If a user clicks through your pages, why would you waste bandwidth on that photo at the bottom of your post, when the user never scrolled there to view it?

    • It’s for saving bandwidth. On a high traffic site, say 2 million of 5 million users visit a blog post with a lot of images on it, but never scroll down. Below the fold, there is 750k of images. That’s going to save you a boatload of bandwidth (1.5 million megabytes…)

    • Permalink to comment#

      It’s to ensure that people remain online while they read the article. If some laptop user instead decides to get “cute” and load the page in a tab over Wi-Fi at home, get on the bus, and continue reading while offline, he won’t be able to see the pictures.

  7. Jacob
    Permalink to comment#

    I personally like the way this website does it:

    http://www.nomachetejuggling.com/2011/11/11/the-star-wars-saga-suggested-viewing-order/

    (Scroll down quickly.)

    • kayan
      Permalink to comment#

      I like how in that one, the img tags use the real src attributes like normal. It’s a whole lot easier to implement, with no need for special markup or JS fallbacks for each image.

      Unfortunately, this seems to defeat the whole purpose of lazy loading. Looking at a network inspector, I saw every image loaded when the page loads, and loaded a second time when scrolling down. Hiding the images temporarily might have some performance benefits, like in low memory environments such as older iPhones, but it’s not preventing unnecessary network traffic the way Coyier’s solution does.

      It would be great if we could get the best of both worlds – ordinary markup and real lazy image loading – but I have doubts about it being possible. Using real src attributes basically guarantees the images will start loading before JS can intervene.

    • Conor
      Permalink to comment#

      yeah, this one works particularly well.

  8. Permalink to comment#

    On FF11, scrolled down, nothing happened :\

  9. Previous comment didn’t appear (maybe spam folder ¿?)

    Your script have a problem with concurrency. While you are lazy loading the image, and if the place holder is still in the clip rectangle and you are scrolling, you will request again and again the image until the image is totally loaded. You have to move out the callback function to remove image from array the first time you requested it.

  10. Andrew
    Permalink to comment#

    I’m having trouble getting this to work in IE (big surprise) with WordPress and loading in the images via PHP. Any ideas how I could get that to work?

  11. Permalink to comment#

    Hi Chris,

    just wanted to mention that I think there’s a mistake in the code. I think you’re using the splice-Method inside the processScroll function wrong – second Parameter should be ‘1’ instead of ‘i’. I had some weird results with splice(i, i) (of course).

    Am I wrong?

    Greetings

    Dominique

  12. Mary
    Permalink to comment#

    Search engines will not be able to find those images, are they?

    • Permalink to comment#

      Hey! Search engines will read the alt tag of the image element, if you have mentioned the alt tags then search engine will find the images.

  13. Permalink to comment#

    no they won’t… I also can’t think of a good way to embed them in another way so SE will see them. You could provide an alternative, standard html page where the images are not lazy loaded for SEs only (catch’em and redirect or simply put a link on the bottom/top of the page).

    • Ian
      Permalink to comment#

      Hey, probably more work than people may like, but one way is to check the user agent to see if it’s any of the popular search engines, then if it is just load the images like you normally would. Although I’m unsure if this will spark a red flag. I imagine there’s a possibility they send alternative user_agents to a site as well and compare content, to detect potential SE manipulation. Just a thought.

  14. Chris: “It’s for saving bandwidth.”

    Doesn’t it also reduce page load time, which can be an SEO factor (if it’s bad enough)? And a usability factor, since it seems like there’s some page functionality that doesn’t work until the DOM is loaded (drives me nuts on our local newspaper site – the page is “frozen” until their dysfunctional server loads all the ads).

  15. Kevin
    Permalink to comment#

    Thanks for the script. Is there a simple way to add an effect? Like a fade in or delay?

  16. Haven’t tried it yet, but imo, a way to gracefully degrade (and probably SEO-friendlier) approach would be to have links to full images.
    You could include some image data (width, height, alt/title) as data- attributes in the link
    Then, via JS, you:

    1) Create the <img /> tag. On the src attribute, you use a blank.gif and on the data-src, you put the URL to full image (that you get from the href attribute on the a element). Optional: for a better user experience, you also set width, height, alt & title, which you get from data- attributes, also on the a element.

    2) You lazy-load them as usual, when user scrolls the page.

    • Permalink to comment#

      the scrapers/spiders/bots don’t usually trigger most js events so none of those attrs would ever fire.

  17. Giuseppe
    Permalink to comment#

    There’s something I think you’ve overlooked.

    If JavaScript is disabled no images will be shown at all, which is no good from a user point of view.

    Some people prefer to browse without JavaScript enabled, and websites should be able to degrade their functionality accordingly.

    In this case, if JavaScript is disabled, it’s better to show all images.
    Even though it cost more in bandwidth terms, but at least the user will be served with a readeable page.

  18. Harlowe Thrombey

    Only Web Developers think Lazy Loading is cool. (The same guys who used to think Ajax was cool… and before that frames… whatever the Design Fad Du Jour is)

    The problem with lazy loading is it prevents quick scanning by the human eye. In fact, Lazy Loading assumes the human eye is incapable of scanning images.

    Google destroyed their Image Search with Lazy Load.

    What do so many Web Developers like to DEVOLVE the ease of browsing?

    • ben
      Permalink to comment#

      try to put a hundred of images on a single page, even smalls
      Not about design, it smoothens visual-heavy pages

  19. Harlowe Thrombey

    Yeah and Google thinks their Image Search is fine, too.

    Monkey Engineers

  20. Sa30
    Permalink to comment#

    lazy load is working in the home page but not in other pages. what might be the problem?

  21. Permalink to comment#

    If i’m using a framework or a CMS, how can i use this script?

  22. Permalink to comment#

    Do search engines crawl the link in the “data-src” attribute ?

  23. Permalink to comment#

    Thanks for the inspiration. I know there are a few lazy load image scripts out there but I created my own: https://github.com/dinbror/blazy which I think is easier to use and comes with more features like horizontal lazy load, multi-serve images depending on size, callback etc.

    I would love to get some feedback on it.

  24. zureshm
    Permalink to comment#

    I copy pasted your js and it didn’t worked, but the script from your demo page worked!

    at the last line

    here it is :-

    addEventListener(‘scroll’,processScroll);

    }(this);​ ——————————–> this didnt worked

    and in your demo page:-
    addEventListener(‘scroll’,processScroll);

      });  -------------------------------------- this worked
    

    I am a beginner. For me most of ur answers didnt work first time :/

  25. stephan
    Permalink to comment#

    Thanks for this.
    I’ve installed 4 versions of lazyload and this paticular script is pulling the best page-test results.
    One question I have is how I can lazyload background images. I have many of them on my site.

  26. Vivek Vikranth
    Permalink to comment#

    Sorry What is lazy loader.?

  27. Vanessa King
    Permalink to comment#

    I have to confess, I’m a web developer who doesn’t think lazy load is all that cool (RE: Harlowe Thrombey’s comment), for one reason: it causes page drag. If the images don’t load quickly enough as you’re scrolling, your browser gets stuck and you end up with horrible, frustrating page drag. I’d rather wait an extra few seconds at the beginning of the page’s load and be able to scroll smoothly all the way to the bottom, than start scrolling and get hung up every 300px.

    I have seen it done well, and if an effect is added and there’s no drag, it looks quite good—clients seem to love it and ask for it fairly often.

    I noticed drag the first time I looked at the reference URL in this post… Is there a way, aside from preloading which defeats the purpose, to insure there’s no drag? Is it slow connections or too-large images causing the issue?

    BTW, thanks for all your work, Chris! I think some of the comments on this post were really unnecessary and out of line—even though I’m not a fan of lazy load, I use your posts as a reference often and appreciate all your work.

    • Permalink to comment#

      You won’t find it useful until you have a website which eats too much bandwidth because of images

  28. Permalink to comment#

    Hey, is the closing ‘a’ tag at the end of the img html code just a mistake < / a > ?

  29. Norbert
    Permalink to comment#

    Has anyone come across any lazy load solutions that don’t require the data-src attribute and will just work for all img tags? I have several websites with lots of imagery but they all use a CMS and I don’t want to re-enter 5 years worth of images that were entered through WYSIWYG content.

  30. John
    Permalink to comment#
  31. Vesa Piittinen
    Permalink to comment#

    Some of you might this solution interesting:

    No data-src attribute, just wrapped img tags. Also doesn’t do lazyloading on IE9 and below, so you won’t get page drag on IE8 that halts all stuff when doing JS. And works fine on iPad too.

  32. Rakesh
    Permalink to comment#

    I want to apply lazy loader for all divs in my website. How can i do this?

  33. Bruno
    Permalink to comment#

    This technique works very nicely for inline images but would it be possible to adapt to work with images loaded by CSS or, in my specific curiosity, third-party’s JS?

    It would be very nice to have such feature integrated or compatible with ResponsiveSlides.

    Or, maybe, with Supersized, which although allow images be defined in a JSON structure (which is great for API consumers) it preloads them unnecesarily, IMHO.

  34. damienmcd

    Works nicely.
    Thanks!

  35. mr-box

    it works on ipad – http://www.mr-box.com

  36. Tim

    How would I load images just before the came into view? If I want an image to load 200 pixels before it appears on viewport, could I change rect.top >= 0 to rect.top >= 200?

  37. Babak
    Permalink to comment#

    Thanks. Works like a charm.

  38. Steve
    Permalink to comment#

    This only works with png? Does it work with jpg? Mine are blank.

  39. Caleb
    Permalink to comment#

    I wrote a lazy loader that can be applied to all elements with about about 80% less code then this. It’s also a lot faster loading and doesn’t bog the website down.

    • Vesa Piittinen
      Permalink to comment#

      A classical case of “code or it didn’t happen”. Telling about this magical code that just works miracles doesn’t bring anything to the table.

  40. Permalink to comment#

    Images are set to blank.gif may not indexed by Google, how to use this way and make it search engine friendly? Any idea? Thank you!

Leave a Comment

Posting Code

Markdown is supported in the comment area, so you can write inline code in backticks like `this` or multiline blocks of code in in triple backtick fences like this:

```
<div>Example code</div>
```

You don't need to escape code in backticks, Markdown does that for you. If anything screws up, contact us and we can fix it up for you.

*May or may not contain any actual "CSS" or "Tricks".