Lazy Loading Images
Outline
-
Lazy Loading Image Overview
-
Different techniques
-
How to achieve better UX
-
Future native support
Mobile
- Overall size: 1.7MB
- Image: 800kb
Desktop
- Overall size: 1.8MB
- Image: 900kb
Around 40%- 50% size of a web page is image! (source)
*Based on HTTPArchive
Why need Lazy Loading Image?
- Performance Improvement
- Cost reduction
Which image can be lazy-loaded?
How to implement
1. Prevent image loading:
- Use <img/> tag
- Use CSS background
2. Trigger the load when image is in viewport
- Use JS Event
- Use Intersection Observer API
Use <img> tag
Don't set the src url to image
<img data-src="https://ik.imagekit.io/demo/default-image.jpg" />
Set src when image is in viewport
const lazyImages = document.querySelectorAll('img.lazy-image');
lazyImages.forEach((image, index) => {
if (isInViewport(image)) {
image.src = image.getAttribute('data-src');
image.classList.remove("lazy-image");
}
});
Use CSS background-image
.lazy-image {
background: #F1F1FA;
}
.background-image {
background-image: url('https://ik.imagekit.io/demo/img/image10.jpeg?tr=w-600,h-400');
}
Toggle class name to add background-image
Detect if element is in viewport
getBoundingClientRect() API
Use Javascript events
function loadLazyImage() {
const lazyImages = document.querySelectorAll('img.lazy-image');
lazyImages.forEach((lazyImage, index) => {
if (isInViewport(lazyImage)) {
setImageSrc(lazyImage);
}
});
}
document.addEventListener("scroll", loadLazyImage);
window.addEventListener("resize", loadLazyImage);
Use Intersection Observer
const lazyImages = document.querySelectorAll('img.lazy-image');
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const image = entry.target;
setImageSrc(image);
imageObserver.unobserve(image);
}
});
});
// Observe all lazy images
lazyImages.forEach(image => {
imageObserver.observe(image);
});
Issues with Lazy Image
- Placeholder is ugly
- Slower to see the content
- ...
To a better UX
- Use right image placeholder
- Add buffer time for image load
- Avoid content shifting
- Defer image render until ready
Use dominant color placeholder
- Find dominant color of image to create placeholder
- Used by Pinterest, Google
Low quality image placeholder (LQIP)
- Use a low quality image as placeholder
- Create the blur effect
- Used by Facebook and Medium
Facebook Technique
-
Scale to 200 byte
-
Send in GraphQL response
Problem
User scrolls fast
Solution
Preload image
Add buffer time to load image
Problem
- Content jump after lazy image loaded
Solution
- Provide size or ratio to keep the layout
Avoid content shifting
Problem
Janky effect of partial render
Solution
Defer until ready
Defer render until ready
src is set
download image
decode image
render image
const newImage = document.createElement('img');
newImage.setAttribute('src', image.getAttribute('data-src'));
newImage.classList.add('image');
newImage.decode().then(() => {
image.parentNode.replaceChild(newImage, image);
});
What is next?
Native support for lazy image in browser is coming...
Available in Chrome 75
<img src="celebration.jpg" loading="lazy" alt="..." />
<iframe src="video-player.html" loading="lazy"></iframe>
- lazy: is a good candidate for lazy loading.
- eager: is not a good candidate for lazy loading. Load right away.
- auto: browser will determine whether or not to lazily load.
Feature detection
<script>
if ('loading' in HTMLImageElement.prototype) {
// Browser supports `loading`..
} else {
// Fetch and apply a polyfill/JavaScript library
// for lazy-loading instead.
}
</script>
But...
Thanks for listening to my talk
References
Copy of Lazy Loading Images
By thientran1707
Copy of Lazy Loading Images
- 141