The CLS Problem with Lazy Loading
Lazy loading images is a powerful performance optimization technique that delays loading off-screen images until they're needed. However, when implemented incorrectly, it can severely impact Cumulative Layout Shift (CLS) - one of Google's Core Web Vitals metrics. CLS measures visual stability by quantifying how much visible content shifts during page load.
The primary cause of CLS with lazy loading is simple: when images load without reserved space, they push existing content around. This creates a jarring user experience where buttons move, text jumps, and users accidentally click wrong elements. The solution isn't to avoid lazy loading, but to implement it correctly with proper dimension management.
Setting Proper Image Dimensions
The foundation of CLS-free lazy loading is proper dimension management. Every image must have explicit width and height attributes that match its intrinsic dimensions. This allows browsers to reserve the correct space before the image loads, preventing layout shifts.
- 1Add width and height attributesAlways include width and height attributes that match the image's actual dimensions. Use the intrinsic size, not the styled size.
- 2Use CSS for responsive sizingSet max-width: 100% and height: auto in CSS to make images responsive while maintaining aspect ratio.
- 3Implement aspect ratio boxesFor responsive designs, use CSS aspect-ratio property or padding-top technique to maintain consistent proportions across breakpoints.
<img src="image.jpg"
width="800"
height="600"
alt="Description"
style="max-width: 100%; height: auto;">Native Lazy Loading Implementation
Modern browsers support native lazy loading through the loading='lazy' attribute. This is the preferred method as it requires no JavaScript, has excellent performance characteristics, and handles CLS prevention automatically when proper dimensions are set.
<img src="image.jpg"
width="800"
height="600"
loading="lazy"
alt="Lazy loaded image">- No JavaScript requiredWorks without any client-side code
- Better performanceBrowser-native implementation is more efficient
- Automatic CLS preventionRespects dimension attributes properly
- Browser supportNot supported in older browsers (needs fallback)
- Less controlLimited customization compared to JavaScript solutions
- Loading thresholdBrowser determines when to load based on its own heuristics
JavaScript Fallback Implementation
For browsers that don't support native lazy loading, you'll need a JavaScript fallback. The Intersection Observer API is the modern standard for this, providing efficient detection of when elements enter the viewport.
- 1Use data-src attributeStore the real image URL in data-src instead of src to prevent immediate loading
- 2Create Intersection ObserverSet up an observer to watch for images entering the viewport
- 3Swap attributes on intersectWhen an image becomes visible, move data-src to src to trigger loading
- 4Add loading class for stylingUse CSS classes to show loading states and handle errors gracefully
// Simple Intersection Observer implementation
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
observer.unobserve(img);
}
});
}, { rootMargin: '200px 0px' });
document.querySelectorAll('img[data-src]').forEach(img => {
observer.observe(img);
});Testing and Debugging CLS Issues
Proper testing is crucial to ensure your lazy loading implementation doesn't harm CLS. Browser developer tools provide excellent visibility into layout shifts, allowing you to identify and fix issues before they impact real users.
- 1Use Chrome DevTools Layout Shift RegionsEnable Layout Shift Regions in Performance panel to visually see shifts during recording
- 2Check Web Vitals extensionInstall the Web Vitals extension for real-time CLS monitoring during development
- 3Test with throttled connectionSimulate slow networks to see how images load progressively and affect layout
- 4Verify across viewport sizesTest responsive behavior at different breakpoints to catch aspect ratio issues
Advanced Techniques and Best Practices
Beyond the basics, several advanced techniques can further optimize your lazy loading implementation. These include combining lazy loading with responsive images, implementing blur-up placeholders, and using modern CSS features for smoother loading experiences.
Automate image optimization with Optimagio
Doing this by hand for every image does not scale. Optimagio optimizes and converts your images (WebP and AVIF) automatically across your API, web app, and CMS — so every page ships the smallest possible files without manual work. See plans and pricing →