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 (
 * expects a list of:  
 * `<img src="blank.gif" data-src="my_image.png" width="600" height="400" class="lazy">`

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

          res = c;
        return res;
    , addEventListener = function(evt, fn){
          ? this.addEventListener(evt, fn, false)
          : (window.attachEvent)
            ? this.attachEvent('on' + evt, fn)
            : this['on' + evt] = fn;
    , _has = function(obj, key) {
        return, 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)
        el.src = src;

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

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

    return (    >= 0
    && rect.left   >= 0
    && <= (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);
    // is not callable under our lovely IE8 
    for (var i = 0; i < query.length; i++) {



Reference URL


  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 :


      to :


    • Kyle Hawk
      Permalink to comment#

      I know this is out of date, but I had this problem too. On touch devices it waits until after the scroll has completed, which on iPhone means an empty image for a few seconds while it slowly stops. The way I fixed it, with the suggestion from Matt, was to add

      addEventListener('touchmove', processScrollMobile);

      And then that write another function that, instead of checking to see if it’s in the viewport, just loads images upon first scroll:

      processScrollMobile = function(){
          for(var i = 0; i < images.length; i++) {
              loadImage(images[i], function() {

      Worked for my cause! Hope it helps.

  3. Anselm
    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:

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

      and in css using modernizr.js:

      .no-js .lazy {
    • Anonymous
      Permalink to comment#

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

    • Pete
      Permalink to comment#

      You could also add a function which parses the DOM to create the data-source after the page is loaded which replaces the src attribute dynamically.

  4. Vincent Voyer
    Permalink to comment#

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

    You’ll find it here :

    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. Effand Bocah nozh
    Permalink to comment#

    this is not work full in my blog,,

    please help me please. . .

  6. Antonio Felix
    Permalink to comment#

    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?

    • Chris Coyier
      Permalink to comment#

      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…)

    • Pino
      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:

    (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. Farzad
    Permalink to comment#

    On FF11, scrolled down, nothing happened :\

  9. Foro Vietnam
    Permalink to comment#

    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. streunerlein
    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?



    • Matt
      Permalink to comment#

      It’s not just that. I think there are several bugs:

                for (var i = 0; i < images.length; i++) {
                  if (elementInViewport(images[i])) {
                    loadImage(images[i], function () {
                      images.splice(i, i);

      splice(i,1) instead of (i,i) as Dominique mentioned.
      the lambda doesn’t bind to i as of the current iteration — it ends up equal to the terminating i. that is, i==images.length. that’s why the splice(i,i) doesn’t break anything — you’re always saying splice(images.length, images.length), which is a nop.
      even if you make a local copy of i so the lambda gets the right index, it’ll still be the index as of the time the loop ran. fire off several lambdas, one fires, and suddenly the indexes in the others may be wrong, as the array has mutated underneath them.

      i ended up turning images into an object, with indexes as properties. that way the indexes aren’t invalidated as things get removed.

  12. Mary
    Permalink to comment#

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

    • Saad
      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.

    • Max Leps
      Permalink to comment#

      I do not think so… what about images search?? will search engine grab the image url from the data-src attribute??

  13. streunerlein
    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. Karl Kelman
    Permalink to comment#

    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. Julián Landerreche
    Permalink to comment#

    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.

    • sean
      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. von
    Permalink to comment#

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

  22. Jesin
    Permalink to comment#

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

  23. dinbror
    Permalink to comment#

    Thanks for the inspiration. I know there are a few lazy load image scripts out there but I created my own: 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 :-


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

    and in your demo page:-

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

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

    • Max Nelson
      Permalink to comment#

      Having the same problem, did you ever discover a solution?

    • Jules Bartow

      Me too.

    • creamidea
      Permalink to comment#

      Hi, did you run the code in the “strict” mode?
      I had met the same question. And I found that it was OK in non-strict-mode.
      Hope this can help you.

  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.

    • Rami
      Permalink to comment#

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

  28. Mateo
    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.

  35. mr-box

    it works on ipad –

  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 >= 0 to >= 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. Terry Lin
    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!

  41. bruno
    Permalink to comment#


    per aps another solution

    while javascript scan images , it can replace src with load gif , and then image is fire , it replace load gif with the url(same as first) placed in title attribute , no ?

  42. Thomas
    Permalink to comment#

    For a isotope/packery based layout which combines lazy loading with fluid images with a varying aspect ratio I see no other option than to apply inline padding-bottom (calculated by php on the server), like mentioned in this thread:
    It works fine, but applying inline css seems like a bad practise. Alternative could be to punt this information in a data attribute and apply the inline css with javascript, prior to invoking the packery/isotope layout. Any thoughts on this?

  43. shri
    Permalink to comment#

    is there any way to get it work without shrinking and not placing the width and height attributes for every image tag ??

  44. Max Maxymenko
    Permalink to comment#

    Amazing, thanks a lot!
    Just added this to my site works like a charm :)

  45. hashem
    Permalink to comment#

    hi sorry
    do not be data-src=””
    mean dont view image

  46. Alex
    Permalink to comment#

    One small issue with this code is that the “_has” function is defined but never used.
    Thanks it works great

  47. Ivo Petkov
    Permalink to comment#

    I would like to show you an update that makes the code SEO-friendly. At you can see I’ve kept the src attribute as it should be (path/to/image.jpg), and I’ve added a srcset with a special value that prevents it from loading. The code is available at

  48. Kirk Clemons
    Permalink to comment#

    This is cool, but my only issue, is that the content bounces. In otherwords the place holder image is not rendered at the correct size, then the original is lazy loaded in and the content around the image shifts around.

    Is there a way around this problem? I could limit the ‘.lazy’ class to just images that will appear below the fold, but my pages are templated so that would be difficult to automate.

  49. Kavi

    I have used this code and its working fine but not working for hidden images can you please give some idea how to implement it for hidden images.

    Thanks in advance

  50. John Friend

    Why does this code use el.parent instead of el.parentNode. The el.parent property appears to be undefined in every browser I tried your demo page in (IE11, Firefox, Chrome, Edge). So, the script never uses the .replaceChild() option which makes me wonder why it’s even there.

  51. Craig

    I’m not suggesting my version is better but it’s a little more succinct. I’m not catering for older browsers except a fallback which has to wait for jQuery to load.

        (function (selector, offset) {
            if (!!document.querySelectorAll) {
                var lazyImages =;
                function elementInViewport(el) {
                    var rect = el.getBoundingClientRect()
                    return ( >= 0 && rect.left >= 0 && ( - offset)<= (window.innerHeight || document.documentElement.clientHeight))
                var processScroll = function () {
                    for (var i = 0; i < lazyImages.length; i++) {
                        if (elementInViewport(lazyImages[i])) {
                            lazyImages[i].setAttribute("src", lazyImages[i].getAttribute("data-src"));
                            lazyImages.splice(i, i);
                if (window.hasOwnProperty("touchmove")) {
                    addEventListener('touchmove', processScroll); // Touch
                } else {
                    addEventListener('scroll', processScroll);  // Mouse
            else {
                $(function () {
                    $("img:not([src])").each(function (i, e) {;
                        $(e).attr("src", $(e).data("src"));
        })("img:not([src])", 500);
  52. Iman Tumorang
    Permalink to comment#

    Any idea with a simple code in JavaScript please. Too much consume my brain computing processor to read the code. Lol :D

  53. Matt K
    Permalink to comment#

    Great script but there is one issue I came across, this will replace the image with the data-src on every scroll event. Meaning as you’re scrolling past it, the image will repeatedly be replaced. Not noticeable with a static image, but throw a gif in there and you can see it’s a big issue. A small update to the loadImage() function will make sure the image is not already loaded before making the switch.

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

Leave a Comment

Posting Code

We highly encourage you to post problematic HTML/CSS/JavaScript over on CodePen and include the link in your post. It's much easier to see, understand, and help with when you do that.

Markdown is supported, so you can write inline code like `<div>this</div>` or multiline blocks of code in triple backtick fences like this:

  function example() {
    element.innerHTML = "<div>code</div>";

We have a pretty good* newsletter.