Reputation: 4191
I am currently trying to update my Website using the new loading="lazy" attribute as shown here: https://web.dev/native-lazy-loading
As seen in the video, everything works as expected, but compared with my waterfall diagram in chrome, it doesn't.
How it looks:
How it should look:
This is how its implemented:
<img class="has-border" src="https://andreramoncombucket.s3.amazonaws.com/static/assets/img/work/personal-website/pw_full.jpg" style="object-fit: cover;" alt="..." loading="lazy">
Upvotes: 38
Views: 55248
Reputation: 1
I had a similar problem and I solved it by putting more images.
According to my tests, Chrome is too eficient for a small quantity of images. Only when there are many images that Chrome begins to do proper lazy loading.
Upvotes: 0
Reputation: 91
Wrap the element in a picture tag to fix the issue in Chromium browsers:
<picture>
<img class="has-border" src="https://andreramoncombucket.s3.amazonaws.com/static/assets/img/work/personal-website/pw_full.jpg" style="object-fit: cover;" alt="..." loading="lazy">
</picutre>
You don't even need to add attributes to the picture element, so I suspect this is still a bug with the browser.
Upvotes: 1
Reputation: 361
There is currently a bug in Firefox: The loading="lazy"
attribute has no effect, if it is placed after the src
attribute.
The fix is simple: place the loading
attribute before the src
attribute.
Working example:
<img
loading="lazy"
src=...
/>
The following will not work in Firefox - images will be loaded immediately (but works in Chrome):
<img
src=...
loading="lazy"
/>
Upvotes: 11
Reputation: 581
It could be because of cache.
If you see here lazy-img in the Network tab that means everything is fine.
You can test on a private window if you want just to double check.
Upvotes: 0
Reputation: 1196
One possible fix is just to implement it yourself with an IntersectionObserver
at the footer of your document.
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
const img = entry.target;
if (entry.intersectionRatio > 0) {
img.setAttribute("src", img.getAttribute("data-src"));
observer.unobserve(entry.target);
}
});
});
//Get images that aren't visible on load
const imgs = document.querySelectorAll("img").filter((img) => {
const { top, left, bottom, right } = img.getBoundingClientRect();
return (
top >= 0 &&
left >= 0 &&
bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
right <= (window.innerWidth || document.documentElement.clientWidth)
);
});
imgs.forEach((elm) => {
//Save src to data-src
elm.setAttribute("data-src", elm.getAttribute("src"));
//Set src to single invisible base64 pixel to minimize jank
elm.setAttribute(
"src",
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P+/HgAFhAJ/wlseKgAAAABJRU5ErkJggg==",
);
//Observe the element when it scrolls into the viewport
observer.observe(elm);
});
Make sure you do it in the footer with a SYNCHRONOUS script tag. If you wait for DOMContentLoaded
or the like, some of the images will have already been requested. E.g.
<html>
<body>
Your body content, including images...
<script>
//PUT YOUR CODE HERE
</script>
</body>
</html>
Notice there are no attributes on the script. If your script tag has a defer
or async
attribute on it or is of type='module'
the javascript won't execute until the image downloads have already begun.
Upvotes: 0
Reputation: 141
optionally if you dont want to change your image size use this
Original code
<img class="has-border" src="..." style="object-fit: cover;" alt="..." loading="lazy">
With working Lazy load with no size restrictions
<img class="has-border" src="..." style="object-fit: cover;" alt="..." loading="lazy" width="auto" height="100%">
Upvotes: 2
Reputation: 397
I had a similar problem, and after some research, I found the solution:
Just need to add width and height to the IMG tag, this is because the browser needs to know the size of the element before applying lazy loading.
Your code:
<img class="has-border" src="..." style="object-fit: cover;" alt="..." loading="lazy">
Your code after adding width and height:
<img class="has-border" src="..." style="object-fit: cover;" alt="..." loading="lazy" width="200px" height="200px">
Another alternative is using inline style:
<img class="has-border" src="..." style="object-fit:cover; height:200px; width:200px;" alt="..." loading="lazy">
Take into consideration I just randomly set the dimensions of the IMG tag to 200px. You can find more information on this web.dev article
hope it helps 👍
Upvotes: 28
Reputation: 1552
I have the worst reason it wasn't working - I forgot to add the width
and height
attributes (they were instead added as style
s in my broken code)
Upvotes: 4
Reputation: 8533
I had a similar issue when trying to implement it.
I use Chrome by default and it was not working. When I tested it in Firefox, it did work. That made me think it was a browser problem.
After digging in a bit more, I found out the "problem" for my case. It might be the same probably for many others.
It turns out Chrome is more impatient than Firefox when loading images tagged as lazy. That means it loads the images much earlier, so an image will not be loaded when it appears at the screen but earlier than that. Firefox, on the other side, is loading the images almost when they are about to be shown at the screen.
The images I was testing were below the fold, but the page was not very long, so Chrome was loading the images anyway.
When I tried it in a much longer article, the images that were deep down the article did load lazily in Chrome as well.
Hope this helps!
Upvotes: 53