How lazy loading images using JavaScript works? - javascript

I am curious about how lazy loading images, images that will be loaded when scrolled to them, works.
Any hint?

Here's a how-to, using plugins: http://www.webresourcesdepot.com/lazy-loading-of-images-resources-you-need/ here's the jquery plugin: http://www.appelsiini.net/projects/lazyload
basically you put a dummy image in your src attribute and add another attribute for the actual image, JS detects the scroll position of the page, and loads the image data once you get close enough to the image. it does that by replacing the src with the source of the actual image.
here's another explanation: http://engineering.slideshare.net/2011/03/faster-page-loads-with-image-lazy-loading/

Solution for 2020+:
There is a native way to lazy load images that already works in some browsers. While standardization is still underway, you can already use it today! Just add the loading attribute to your image tags and set it to "lazy":
<img
src="picture.jpg"
width="100"
height="100"
alt="descriptive text"
loading="lazy"
>
And that's it. Compatible browsers will load that image lazily as soon as the current viewport is close enough.
Further information available here:
Native lazy-loading for the web
Request to be added in the HTML specification
Current browser support
If you need a solution for older browsers, you should have a look at Lazy loading on MDN.

And example on how to do this, easily.
<img src="/images/lazy.jpg" data-real-src="/images/company-1.jpg">
The "lazy.jpg" can be used on all images, which will result in really just one image is loaded (and it's a 1x1px small weight image). So, consider I'm having a list of 250 stores to visit, with a company logo for each. Could look like this:
<img src="/images/lazy.jpg" data-real-src="/images/company-1.jpg">
<img src="/images/lazy.jpg" data-real-src="/images/company-2.jpg">
<img src="/images/lazy.jpg" data-real-src="/images/company-3.jpg">
...
Then comes the magic!
Put this in your javascript file:
$('img[src="/images/lazy.jpg"]').each(function(index, el) {
$(el).attr('src', $(el).data('real-src'));
});
And wacka-wacka, all the lazy.jpg images will be replaced by their "real" images. The purpose getting your html page loading faster (since those 250 companies all have the same "logo" in lazy.jpg :) ... But the JS takes care of it all after DOM finished loaded.
This is a jQuery solution of course. Can be done with pure js, as well.

You can use justlazy, which is independent of dependencies like jQuery and very lightweight:
The only call you need is:
var placeholders = document.querySelectorAll(".load-if-visible");
for (var i = 0; i < placeholders.length; ++i) {
Justlazy.registerLazyLoad(placeholders[i]);
}
The placeholders have to be the following structure:
<span data-src="url/to/image" data-alt="some alt text"
data-title="some title" class="load-if-visible">
</span>
For SEO reasons you can use any other placeholder (e.g. placeholder image).
Additionally there is a guide how to use it and some general things about lazy loading of images.

Browser-level native lazy-loading is finally available.
<img src="image.png" loading="lazy" alt="…" width="200" height="200">
<img loading=lazy> is supported by most popular Chromium-powered browsers (Chrome, Edge, Opera), Firefox and the implementation for WebKit (Safari) are in progress. Can I use has detailed information on cross-browser support. Browsers that do not support the loading attribute simply ignore it without side-effects.
Improved data-savings and distance-from-viewport thresholds

Lazy loading images using conventional way of attaching listener to scroll events or by making use of setInterval is highly non-performant as each call to getBoundingClientRect() forces the browser to re-layout the entire page and will introduce considerable jank to your website.
Use Lozad.js (just 569 bytes with no dependencies), which uses InteractionObserver to lazy load images performantly.

2021 - keep it simple...
Lots of plugin recommendations here, and depending on your use case those may be valuable to you.
If you can't be bothered to write this short snippet of code below, or you need callbacks already built out then you can use this plugin I built which is based on this exact answer and only 0.5kb when minified. My plugin, Simply Lazy, can even work with IE if you simply add a polyfill.
At the end of the day if you just need to lazy load some images then it's as simple as:
<img data-src="your-image-path-here" class="lazyload" />
And:
let observer = new IntersectionObserver((entries, observer) => {
entries.forEach(function (entry) {
if (entry.intersectionRatio > 0 || entry.isIntersecting) {
const image = entry.target;
observer.unobserve(image);
if (image.hasAttribute('src')) {
// Image has been loaded already
return;
}
// Image has not been loaded so load it
const sourceUrl = image.getAttribute('data-src');
image.setAttribute('src', sourceUrl);
image.onload = () => {
// Do stuff
}
// Removing the observer
observer.unobserve(image);
}
});
});
document.querySelectorAll('.lazyload').forEach((el) => {
observer.observe(el);
});
Using the Intersection Observer API makes this all very simple. You can also use it within the shadowRoot and it works fine there as well.
I've also found this article helpful to understand what is going on here.

There's many ways to implement lazy loading. The process is just that you load what you need. You can lazy load anything in the software scene. On websites most use it when loading in images and it's because most of the website is pretty much just images. I mean the artwork of the website plus the actual persons pictures they could have thousands of images on your server. This normally causes a slow down when you try and load all of them at the same time. At some point it starts to slow down the process. So, lazy loading is normally done for large websites. Like I said you can do this numerous ways. one way was already given. Have the img tag already loaded but the src part points to a dummy file something that is small in size. Don't use a image that is graphic or a picture... use something like a grey block.. or could use nothing. Then when the scroll part is near the scrolling point where the images are close by. It will run a function where it will replace the src with the real image link. Another way is to use ajax and the scroll point when close will append... load in the actual html code with the image in the src. This is what I actually use. I write a PHP file to lazy load images, data, text.
The whole point of this method is to download the files from a website when needed. When a image is loaded it's actually being downloaded from your server. So, the downloading process plus the actual loading time can increase when you start dealing with larger image files and too many of them.

Related

Optimizing 1500 images (100kb) each on a single web page? [duplicate]

I am curious about how lazy loading images, images that will be loaded when scrolled to them, works.
Any hint?
Here's a how-to, using plugins: http://www.webresourcesdepot.com/lazy-loading-of-images-resources-you-need/ here's the jquery plugin: http://www.appelsiini.net/projects/lazyload
basically you put a dummy image in your src attribute and add another attribute for the actual image, JS detects the scroll position of the page, and loads the image data once you get close enough to the image. it does that by replacing the src with the source of the actual image.
here's another explanation: http://engineering.slideshare.net/2011/03/faster-page-loads-with-image-lazy-loading/
Solution for 2020+:
There is a native way to lazy load images that already works in some browsers. While standardization is still underway, you can already use it today! Just add the loading attribute to your image tags and set it to "lazy":
<img
src="picture.jpg"
width="100"
height="100"
alt="descriptive text"
loading="lazy"
>
And that's it. Compatible browsers will load that image lazily as soon as the current viewport is close enough.
Further information available here:
Native lazy-loading for the web
Request to be added in the HTML specification
Current browser support
If you need a solution for older browsers, you should have a look at Lazy loading on MDN.
And example on how to do this, easily.
<img src="/images/lazy.jpg" data-real-src="/images/company-1.jpg">
The "lazy.jpg" can be used on all images, which will result in really just one image is loaded (and it's a 1x1px small weight image). So, consider I'm having a list of 250 stores to visit, with a company logo for each. Could look like this:
<img src="/images/lazy.jpg" data-real-src="/images/company-1.jpg">
<img src="/images/lazy.jpg" data-real-src="/images/company-2.jpg">
<img src="/images/lazy.jpg" data-real-src="/images/company-3.jpg">
...
Then comes the magic!
Put this in your javascript file:
$('img[src="/images/lazy.jpg"]').each(function(index, el) {
$(el).attr('src', $(el).data('real-src'));
});
And wacka-wacka, all the lazy.jpg images will be replaced by their "real" images. The purpose getting your html page loading faster (since those 250 companies all have the same "logo" in lazy.jpg :) ... But the JS takes care of it all after DOM finished loaded.
This is a jQuery solution of course. Can be done with pure js, as well.
You can use justlazy, which is independent of dependencies like jQuery and very lightweight:
The only call you need is:
var placeholders = document.querySelectorAll(".load-if-visible");
for (var i = 0; i < placeholders.length; ++i) {
Justlazy.registerLazyLoad(placeholders[i]);
}
The placeholders have to be the following structure:
<span data-src="url/to/image" data-alt="some alt text"
data-title="some title" class="load-if-visible">
</span>
For SEO reasons you can use any other placeholder (e.g. placeholder image).
Additionally there is a guide how to use it and some general things about lazy loading of images.
Browser-level native lazy-loading is finally available.
<img src="image.png" loading="lazy" alt="…" width="200" height="200">
<img loading=lazy> is supported by most popular Chromium-powered browsers (Chrome, Edge, Opera), Firefox and the implementation for WebKit (Safari) are in progress. Can I use has detailed information on cross-browser support. Browsers that do not support the loading attribute simply ignore it without side-effects.
Improved data-savings and distance-from-viewport thresholds
Lazy loading images using conventional way of attaching listener to scroll events or by making use of setInterval is highly non-performant as each call to getBoundingClientRect() forces the browser to re-layout the entire page and will introduce considerable jank to your website.
Use Lozad.js (just 569 bytes with no dependencies), which uses InteractionObserver to lazy load images performantly.
2021 - keep it simple...
Lots of plugin recommendations here, and depending on your use case those may be valuable to you.
If you can't be bothered to write this short snippet of code below, or you need callbacks already built out then you can use this plugin I built which is based on this exact answer and only 0.5kb when minified. My plugin, Simply Lazy, can even work with IE if you simply add a polyfill.
At the end of the day if you just need to lazy load some images then it's as simple as:
<img data-src="your-image-path-here" class="lazyload" />
And:
let observer = new IntersectionObserver((entries, observer) => {
entries.forEach(function (entry) {
if (entry.intersectionRatio > 0 || entry.isIntersecting) {
const image = entry.target;
observer.unobserve(image);
if (image.hasAttribute('src')) {
// Image has been loaded already
return;
}
// Image has not been loaded so load it
const sourceUrl = image.getAttribute('data-src');
image.setAttribute('src', sourceUrl);
image.onload = () => {
// Do stuff
}
// Removing the observer
observer.unobserve(image);
}
});
});
document.querySelectorAll('.lazyload').forEach((el) => {
observer.observe(el);
});
Using the Intersection Observer API makes this all very simple. You can also use it within the shadowRoot and it works fine there as well.
I've also found this article helpful to understand what is going on here.
There's many ways to implement lazy loading. The process is just that you load what you need. You can lazy load anything in the software scene. On websites most use it when loading in images and it's because most of the website is pretty much just images. I mean the artwork of the website plus the actual persons pictures they could have thousands of images on your server. This normally causes a slow down when you try and load all of them at the same time. At some point it starts to slow down the process. So, lazy loading is normally done for large websites. Like I said you can do this numerous ways. one way was already given. Have the img tag already loaded but the src part points to a dummy file something that is small in size. Don't use a image that is graphic or a picture... use something like a grey block.. or could use nothing. Then when the scroll part is near the scrolling point where the images are close by. It will run a function where it will replace the src with the real image link. Another way is to use ajax and the scroll point when close will append... load in the actual html code with the image in the src. This is what I actually use. I write a PHP file to lazy load images, data, text.
The whole point of this method is to download the files from a website when needed. When a image is loaded it's actually being downloaded from your server. So, the downloading process plus the actual loading time can increase when you start dealing with larger image files and too many of them.

What is the best method for lazy load?

I need to eliminate image render-blocking and i use this little script for this
<img data-src>
$('img').each(function() {
$(this).attr('src', $(this).data('src'));
});
It is good for all browser or it is better to use this plugin https://plugins.jquery.com/lazyload/ ?
You could add this CSS rule to avoid the broken image icon showing up :
img[src=''],
img:not([src]) {
opacity: 0;
}
This way, images with no src won't show.
Your code should work in all browsers, but you may want to use some of that Lazy Load Plugin features. For example, it is able to load images when they’re really needed (that is, lazy), not when they’re outside of user-visible area. Your code will try to download all images at the same moment, even if no one is needed.
Consider adding support for robots or users that do not have JavaScript enabled:
<noscript>
<img alt="…" src="…"/>
</noscript>
<img alt="…" data-src="…"/>
Actually, browsers by default load images somewhat lazily. An image on top of web page does not suspend rendering of remaining parts. As Image data is fetched from server browsers paint the reserved space for images in parallel to rendering the other elements.
Your code generates an image and loads it without attaching it to DOM. It is not lazy loading, it may be pre-loading in some context.
Lazy loading is: not beginning to download images from server until their reserved space is visible on browsers view-port. It is used in cases like your page is longer than the view port and there are images whose position stays at a lower portion of the page. Until you scroll to that position you don't load the images.
So if you want to use benefits of lazy loading you should choose the plugin option.

How to force browsers prefetch images in first 6 parallel connections

I've found a lot of techniques to preload images both with CSS and JS, but none of them was able to REALLY preload images the way I need, or more specifically in the order I need.
Simply put the browser will preload all images and stuff in one block, but the order in which each image will be downloaded by the browser is totally on his own calculation, mostly (and totally reasonably) the top most elements in the document will be downloaded first.
Unfortunately this is quite true in my tests with <img> elements only; for other elements with something like background images it's not really like that, even if the images are used as background for the <body> element for example.
The only solution this far that worked the way I needed was to place some <img>elements right after the <body>tag and set them with style="display:none". This is working, but rather ugly and terribly rough way imo to achieve this.
I'm also a bit concerned for SEO, since bots will find right at the start of the document some hidden images just for this purpose (I'm mostly preloading images for preloaders effects like "loading.." with a small logo image).
I was quite charmed with a super brilliant solution I saw to preload images with a pseudo element on the body like this body:before and then use multiple background images. While this technique indeed works to preload, it won't effect the loading order priority... very sad it's so perfect! :(
Isn't there really any other way to force to preload stuff with top priority over the rest of the assets without cluttering the top of the document with hidden images?
UPDATE
As I explain in the comments below, I'm not concerned in having the images loaded in a particular order, I want them to be downloaded BEFORE the most part of the assets and other item in the "download" chart, so that the images will render almost instantly inside the browser along with normal CSS layout rendering when the page is accessed.
UPDATE 2
More info: the term "preload" is indeed misguiding, a more close term for what I'm looking for could be "prefetch" but basically it goes like this:
Most browsers download 6 requests in parallel at a time, holding up the rest of the downloads. If what you "really" need is in this top 6, you are lucky, else it in the next 6, or maybe the one after and so on.
What I'm trying to do is find a proper way to tell "hey download this first please" and in particular "this image".
As pointed out by #farkas in the answers below rel="subresource" is indeed a good start but as pointed here, it works mostly as "[..]suggests it’s actually downloaded as a lower priority than stylesheets/scripts and fonts but at an equal or higher priority than images", so it will indeed be loaded first than many other things, but still no proper way to break in those 6 gold top spots.
As you can see, the browser downloaded first the styles, THEN 1 of the images I needed loaded ASAP, then the scripts, leaving out the other 2 images I needed to be downloaded with top priority.
To be noted tho that I've placed all my scripts not in the head, they are all placed at the bottom before the closing </body>, and also (as stated on top of my question) I've marked my images RIGHT AFTER the opening <body> tag, but only dark-pattern.jpg has been downloaded first, the other 2 were postponed
...
</head>
<body>
<img src="dark-pattern.jpg" style="display:none">
<img src="preloader.jpg" style="display:none">
<img src="xs-style.png" style="display:none">
.. rest of code
...
I'd like to know a proper way to say, "please have a spot for my pictures, just download the stiles, the script can come later".
Is it possible to achieve this?
I've found some more detail on this matter in here too, but nothing on my specific request apart rel="subresource"
http://www.stevesouders.com/blog/2008/03/20/roundup-on-parallel-connections/
http://sgdev-blog.blogspot.it/2014/01/maximum-concurrent-connection-to-same.html
http://andydavies.me/blog/2013/10/22/how-the-browser-pre-loader-makes-pages-load-faster/
PS. if all this thing has a specific technical name, please let me know so I finally can give the beast a name, thanks :P
Loading images using CSS or JS, will be always slower then using HTML. This is due to the fact that CSS and JS is loaded and parsed after HTML. Additionally to that, the browser optimizes this by using a speculative preload parser.
So if your images are already in HTML, you won't reorder your img downloads, if you add a preload script for those images.
Therefore you have basically two options:
Load images as soon as possible by adding them top (either with your hidden img or using link rel="subresource" (Chrome only)
Delay loading all other non-crucial assets using a lazyloader
Try this:
var all = ['img1.jpg','img2.jpg'];
function onAllImagesLoaded() { alert('loaded!'); }
function preload() {
var i = new Image();
var src= all.pop();
if (!src) {
onAllImagesLoaded();
return;
}
i.src = src;
i.onload = preload;
}
preload();
There are some issues with cached images in IE, sometimes it may omit onload call for cached resources.
Edit
You can also use nice plugin designed to track all images loading (but it doesn't preserve images order, all images are loaded simultaneously):
http://imagesloaded.desandro.com/

Speeding up Page Loads for Image Background

Working Environment: I have a website that must have an image background (pretend its a math problem and there is no choice but to accept this).
Is there a way for me to format my html and CSS so that background loads faster?
One Idea I had was instead of having the "body" carry the image background, to instead partition the site into rows (using the tag) in the hopes the browser will load the divs, hence it can present some of the visible portions of the site before having loaded EVERYTHING.
I'm pretty sure my method of manual div separation (And setting backgrounds of each slice) isn't the the most efficient approach to this. What is the best way to carry out this technique?
There are many optimizations that you can do to images so that they load faster.
In case of a png image, use services http://pngquant.org/ to achieve lossy
compression of images without much loss of image detail. Or lossless compression using tools like http://optipng.sourceforge.net/
If the image is primarily geometrical, consider using maps and areas.
Use server side gzip compression.
Prevent display of loading images by using lazy loading techniques.
Use Google Page Speed to optimize the site further so as to use the available bandwidth efficiently.
IMHO simplest way to do website with image background is lazy loading of this image. Do it like here
HTML:
<body>
...
</body>
and CSS:
.dom-loaded {
background-image: url('url-to-image');
}
and fininshing with JS (add dom-loaded to body element after your DOM will be fully loaded):
<script type="text/javascript">
function lazyLoad() {
$('body').addClass('dom-loaded');
}
if (window.addEventListener)
window.addEventListener("load", lazyLoad, false);
else if (window.attachEvent)
window.attachEvent("onload", lazyLoad);
else window.onload = lazyLoad;
</script>
Here You have working jsFiddle (with setTimeout just to show delay): http://jsfiddle.net/37vb4npa/1/
Also You need to remember about image optimization (for example ImageOptim - https://imageoptim.com/pl.html, or something online like SmushIt - http://www.smushit.com/ysmush.it/). And remember about other speed optimization stuff.
Your idea is a little similar to what Patrick's Hamman "Breaking News at 1000ms" slideshow is about - https://speakerdeck.com/patrickhamann/breaking-news-at-1000ms-front-trends-2014 - You'll find there some nice & advanced technics to speed website.
Also You can do lazy loading with plugin: http://www.appelsiini.net/projects/lazyload/enabled_background.html
1)first you need a transparent image 1x1 pixel just set this data uri as src default attribute , dont keep src attribute empty otherwise broswer call current page url which will increase extra http request
data:image/gif;base64,R0lGODlhAQABAAAAACwAAAAAAQABAAA=
2)then after onload event add your image url in src attribute.

javascript lazy loading the progressive enhancement way?

I'm building a website for a gallery owner that has a lot of images per webpage.
Therefore I want to lazy load the images on the webpage, making the initial load
less heavy. However, I would like to implement this in a "progressive enhancement" way.
I've found a lot of lazy loading methods but they all require fiddling with the html code
in such a way that the webpage would be useless with javascript turned off. (eg. the src attribute of the img tags remains unset until the images is lazy loaded).
To implement a lazy loading method progressivly I think one would need the following:
prevent the browser from fetching the images, even though thers are on the page,
but only do this when javascript is on (so on non-javascript browsers, the images still
load as normal). This should be done without altering the html.
save the src attribute in a data-src attribute
sequentually load the images when scrolling down
Of these three steps the first one seems the hardest one. Even this stackoverflow discussion did not provide an answer that doesn't ruin progressive enhancement.
Has anyone got any ideas?
Since none has come up with an answer, I'll post what I found a reasonable solution.
This problem boils down to the following: while we want to prevent the browser from downloading the images when javascript is turned on, we must be sure the images are downloaded
when javascript is turned off or not available.
It is hard to consistently use javascript to stop loading images on a page when they are
in the "normal" format:
<img src="path/to/image.jpg"></img>
To stop the images from downloading we'd have to remove their src attributes, but in order
to do this, the DOM should be loaded already. With the optimisations a lot of browsers have nowadays it is hard to guarantee that the images aren't downloading already.
On top of that, we certainly want to prevent interrupting images that are already downloading,
because this would simply be a waste.
Therefore, I choose to use the following solution:
<img data-src="path/to/image.jpg" class="lazy"></img>
<noscript>
<img src="path/to/image.jpg"></img>
</noscript>
Notice how the images outside of the noscript tag have no src but a data-src attribute instead. This can be used by a lazyloading script to load the images one by one for instance.
Only when javascript is not available, will the images inside the noscript block
be visible, so there's no need to load the .lazy images (and no way to do this, since
javascript is unavailable).
We do need to hide the images though:
<noscript>
<style>
.lazy {
display: none;
}
</style>
</noscript>
Like the img tags inside the noscript block, this style block will only be visible to the browser when javascript is unavailable.
On a related note: I thought I could reduce the html size by not putting a src or data-src attributes on the lazy images at all. This would be nice because it eliminates
the redundant url from the page, saving us some bandwidth.
I thought I could pluck the src attribute out of the noscript block using javascript anyways. However, this is impossible:
javascript has no access to the contents of a noscript block. The above scheme is therefore
the most efficient I could come up with.
Not specifying a src attribute is invalid HTML, which is unfortunately how most lazy image loaders work.
I am working on a lazyloader that uses valid html markup, github link:
https://github.com/tvler/lazy-progressive-enhancement
A lazyloaded image would be declared by wrapping it in a noscript element:
<noscript><img alt="hello!" src="..."></noscript>
and the final outputted html would be
<img alt="hello!" src="...">.
You can view the whole project on github, which deals with batch loading, event hooking & more, but here's the basic functionality at the scope of a single noscript image:
var noscript = document.querySelector('noscript'), img;
(img = document.createElement('div')).innerHTML = noscript.textContent;
noscript.parentElement.replaceChild(img.firstChild, noscript);

Categories

Resources