UPDATE: This is pretty old. If you’re looking to lazy load images these days, I’d recommend looking at:
- The Complete Guide to Lazy Loading Images
- A Native Lazy Load for the Web Platform
- Tips for rolling your own lazy loading
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);
See the Pen
Lazy Loading Images by Chris Coyier (@chriscoyier)
on CodePen.
You got a demo?
Link above called “Reference URL”
Tried to test in my site. Working fine.
Here’s a demo, from this awesome related lib (Which I couldn’t find linked here yet): http://afarkas.github.io/lazysizes/
Much more code there, no idea what else it’s handling, but it just works perfectly!
Check it out.
https://css-tricks.com/examples/LazyLoading/
My bad. Its not working on iPad, is it? Nothings happening on my iPad2.
Same here on iPad 3 — nothing happens, no fallback to see, even with the last updated version Feb 23, 2014…
To get this to work on iPad all you should need to do is change :
addEventListener(‘scroll’,processScroll);
to :
addEventListener(‘touchmove’,processScroll);
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
And then that write another function that, instead of checking to see if it’s in the viewport, just loads images upon first scroll:
Worked for my cause! Hope it helps.
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 ;)
@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.
you can use a simple fallback in the markup:
and in css using modernizr.js:
@Robin you should always provide fallback for users without JavaScript support.
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.
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
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.
Hi Vincent! Does this plugin work with background-image property instead of using tags? Thank you!
this is not work full in my blog,,
please help me please. . .
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.
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…)
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.
Hi, for best score with PageSpeed Insights. But for better experience with mobile…
But it’s not work with firefox and privacy hard setting :- (
Lazy Loading images is for postponing loading of images outside the browser viewport. The idea is that those images does not need to take up bandwidth until just before they are needed, making room for other resources to be loaded faster.
Ultimately making the web page load faster.
to avoid server hanging due to multiple heavy load requests
I give you…..
A jQuery version of the same thing!
Have a look, feel free to criticise or suggest improvements:
http://jsfiddle.net/g8THY/6/
It’s smaller than the original but does the same thing, which could be a good thing if you happen to be making use of jQuery already….
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.)
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.
yeah, this one works particularly well.
On FF11, scrolled down, nothing happened :\
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.
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?
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
It’s not just that. I think there are several bugs:
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.
Search engines will not be able to find those images, are they?
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.
I do not think so… what about images search?? will search engine grab the image url from the data-src attribute??
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).
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.
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).
Thanks for the script. Is there a simple way to add an effect? Like a fade in or delay?
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
) asdata-
attributes in the linkThen, via JS, you:
1) Create the
<img />
tag. On thesrc
attribute, you use ablank.gif
and on thedata-src
, you put the URL to full image (that you get from thehref
attribute on thea
element). Optional: for a better user experience, you also setwidth
,height
,alt
&title
, which you get fromdata-
attributes, also on thea
element.2) You lazy-load them as usual, when user scrolls the page.
the scrapers/spiders/bots don’t usually trigger most js events so none of those attrs would ever fire.
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.
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?
try to put a hundred of images on a single page, even smalls
Not about design, it smoothens visual-heavy pages
Yeah and Google thinks their Image Search is fine, too.
Monkey Engineers
lazy load is working in the home page but not in other pages. what might be the problem?
If i’m using a framework or a CMS, how can i use this script?
Do search engines crawl the link in the “data-src” attribute ?
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.
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);
I am a beginner. For me most of ur answers didnt work first time :/
Having the same problem, did you ever discover a solution?
Me too.
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.
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.
Sorry What is lazy loader.?
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.
You won’t find it useful until you have a website which eats too much bandwidth because of images
Hey, is the closing ‘a’ tag at the end of the img html code just a mistake < / a > ?
Yeah that was a mistake, fixed, thanks!
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.
parse image tags in the database
Be lazy instead ;)
https://github.com/dinbror/blazy
Some of you might this solution interesting:
http://codepen.io/Merri/pen/IiqEu
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.
I want to apply lazy loader for all divs in my website. How can i do this?
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.
Works nicely.
Thanks!
it works on ipad – http://www.mr-box.com
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
torect.top >= 200
?Thanks. Works like a charm.
This only works with png? Does it work with jpg? Mine are blank.
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.
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.
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!
Hi
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 ?
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:
https://stackoverflow.com/questions/23416880/lazy-loading-with-responsive-images-unknown-height/23417812#23417812
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?
is there any way to get it work without shrinking and not placing the width and height attributes for every image tag ??
Yes there is.
I’ve put together a short post that explains how: http://afroleft.com/lazy-loading-responsive-images/
Amazing, thanks a lot!
Just added this to my site works like a charm :)
hi sorry
do not be data-src=””
mean dont view image
Hello,
One small issue with this code is that the “_has” function is defined but never used.
Thanks it works great
Hi,
I would like to show you an update that makes the code SEO-friendly. At http://ivopetkov.com/b/lazy-load-responsive-images/ you can see I’ve kept the
src
attribute as it should be (path/to/image.jpg), and I’ve added asrcset
with a special value that prevents it from loading. The code is available at https://github.com/ivopetkov/responsively-lazyThis 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.
Kick, I wrote a how to on this a few years ago http://afroleft.com/lazy-loading-responsive-images/
Hope that helps you :)
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
Why does this code use
el.parent
instead ofel.parentNode
. Theel.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.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.
Any idea with a simple code in JavaScript please. Too much consume my brain computing processor to read the code. Lol :D
I wrote a very simple lazyload script which also uses the noscript tag so no-js users would see images too. I created it after I tried and tested different scripts (but i didn’t like anyone 100%) and I decided to put together the good things of all those scrips. Get my script here and let me know: https://jsfiddle.net/nhed5ojy/3/
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.
Thx Matt K,
this makes the scrolling a lot smoother!
Thanks! But, I have one issue: if pictures is in absolute position, it doesn`t work, here is screenshot http://joxi.ru/VrwogogCO4bdpr
The loading time of online pages is key down to the maximum. One way to improve this aspect is to use Lazy Load, which consists of loading a content on soil! In this DevCast we talked about the development time of DevMedia, which recently used this technique and presented in this video what was needed for this.
http://www.devmedia.com.br/adoramos-ajax/37919
Hi , can you make an update for background: url();
i need that
regards
:)
Very helpful, appreciate the vanilla JS solution.
Just a quick general question though. Is there any benefit to creating a new Image() in the loadImage() function and then using it to replace the
<img>
in the markup like the provided code does, as opposed to directly overwriting the source of the<img>
in the markup (e.gel.src = el.getAttribute('data-src');
) ?This example works when you have
srcset=""
andsizes=""
within theimg
tag?I saw several requests here to make this plugin work with background images, plus I also needed that feature, so I tweaked your plugin and added the feature.
Nice!
Hello do you have a demo?
Best Regards
Yes! Here’s one right here:
https://css-tricks.com/examples/LazyLoading/
One question, with lazy load the images will be indexed in google?
How does this work for an arbitrary amount of images from a directory? Say you’re using a php script to generate the list of images for example… So far it hasn’t worked for me.
Hi, thanks for sharing snippets like this :-)
I often use another approach, which might be of interest to some: https://medium.com/@iliketoplay/lazy-loading-a-flexible-and-performant-approach-5a46b97ef60f
Thanks for the awesome article. If you guys out there using React, i have built a Component which is pretty easy to use and integrate.
check out the demo here:
https://react-simple-img.now.sh/
Shouldn’t you be using the intersection observer now? I’ve read that it’s significantly better than doing the manual calculation with getBoundingRect
Very helpful I usually get stuck in that. Thank u.
Here is a modification I made for my site, this one makes it so you don’t need to add the “lazy” class, only the “data-src”. It also adds “data-background” for background-image css instead of src.
images.splice(i, i);
Don’t you think it’s wrong in here.
You are splicing ‘i’ elements in each iteration.
Doesn’t splicing change indices while looping?
Finally Implemented Lazy Loading to my website. Thanks man