Front-End Performance Optimization: The Principle and Implementation of Image Lazy Loading
1. The Concept and Value of Lazy Loading
Lazy Loading is a technique that delays the loading of non-critical resources. For images, it means loading only the images within the current viewport, while images outside the viewport are loaded when the user scrolls to their position.
Core Value:
- Reduces the number of HTTP requests on the first page load, improving the speed of the first screen rendering.
- Saves user data (especially on mobile devices).
- Reduces server load.
2. Implementation Principle
The key to lazy loading is determining whether an image has entered the viewport. Specific steps:
- Temporarily store the image's
srcattribute in the page (e.g., indata-src), and initially setsrcto empty or a placeholder image. - Listen for scroll events (or use the Intersection Observer API) to calculate the relative position of the image to the viewport.
- When the image enters the viewport, assign the value of
data-srctosrc, triggering the image load.
3. Traditional Implementation (Based on Scroll Events + getBoundingClientRect)
Step 1: HTML Structure Preparation
<img data-src="real-image-url" src="placeholder-or-empty-url" class="lazy-img" />
Step 2: Determine if the Image is in the Viewport
Use Element.getBoundingClientRect() to get the image's position relative to the top of the viewport:
function isInViewport(el) {
const rect = el.getBoundingClientRect();
return rect.top >= 0 && rect.top <= window.innerHeight;
}
Note: A buffer zone (e.g., loading 100px in advance) can be added to improve the experience:
rect.top <= window.innerHeight + 100;
Step 3: Scroll Listening and Loading
const lazyImages = document.querySelectorAll('.lazy-img');
function lazyLoad() {
lazyImages.forEach(img => {
if (img.dataset.src && isInViewport(img)) {
img.src = img.dataset.src; // Trigger loading
img.removeAttribute('data-src'); // Avoid duplicate loading
}
});
}
// Initial check once
lazyLoad();
// Debounce optimization for scrolling
window.addEventListener('scroll', throttle(lazyLoad, 200));
Debouncing/Throttling: Avoid performance issues caused by frequent triggering of scroll events.
4. Modern Implementation (Intersection Observer API)
Intersection Observer is a native browser API that efficiently listens to the intersection state of elements with the viewport, eliminating the need for manual position calculations.
Step 1: Create Observer
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) { // Element enters the viewport
const img = entry.target;
img.src = img.dataset.src;
observer.unobserve(img); // Stop observing loaded images
}
});
}, {
rootMargin: '100px', // Trigger loading 100px in advance
});
Step 2: Bind Images That Need Lazy Loading
document.querySelectorAll('.lazy-img').forEach(img => {
observer.observe(img);
});
Advantages:
- Automatically manages intersection detection, no need to manually listen for scroll events.
- Better performance, avoiding main thread blocking.
5. Optimization and Considerations
- Placeholder Strategy: Use minimal Base64 placeholder images or CSS background colors to avoid layout shifts.
- Responsive Images: When combining
srcsetandsizesattributes, the real URLs can be placed indata-srcset. - SEO-Friendly: Ensure search engines can crawl the real image URLs (e.g., via
<noscript>tag fallback). - Error Handling: Listen for image load failure events and replace with a default image.
6. Summary
Lazy loading significantly improves page performance through "on-demand loading." The traditional approach relies on scroll events and position calculations, while the modern approach uses Intersection Observer for a more concise and efficient solution. In actual development, it is necessary to choose the implementation method based on specific scenarios and pay attention to compatibility and user experience optimization.