How to lazy load an image in CSS
Mastering Lazy Loading for CSS Background Images Dealing with image optimization and lazy loading is a critical aspect of modern web performance. While native...
Mastering Lazy Loading for CSS Background Images
Dealing with image optimization and lazy loading is a critical aspect of modern web performance. While native HTML elements like <img> offer straightforward attributes like loading="lazy", applying this concept directly to CSS properties, specifically background-image, requires a slightly different, more programmatic approach. As senior developers, we know that the browser prioritizes rendering visible content, and loading large background assets unnecessarily slows down initial page load, impacting Core Web Vitals significantly.
The snippet you provided demonstrates how you style an element using a CSS background:
.image--about {
background: url(../img/ZIZF.gif) no-repeat center;
background-size: cover
}
The challenge here is that the browser must immediately know the URL of ../img/ZIZF.gif to render the background, which defeats the purpose of lazy loading if that image is far down the page or off-screen initially. Therefore, we cannot rely solely on HTML attributes; we must use JavaScript to control when that CSS rule is applied or when the image itself is loaded.
The Strategy: Intersection Observer for Backgrounds
Since CSS background loading is inherently tied to rendering flow, the most effective solution involves using the Intersection Observer API. This API allows us to asynchronously observe changes in the visibility of an element (or its container) and trigger actions only when that element enters the viewport.
For lazy loading images loaded via CSS backgrounds, the strategy shifts from "lazy loading the image" to "lazy loading the application of the background style." We will initially hide the content or use a placeholder until the actual image is required.
Step-by-Step Implementation
Here is how you can implement this pattern:
- Use a Placeholder: Instead of applying the heavy background immediately, apply a minimal initial state.
- Observe Visibility: Use JavaScript to watch when the element scrolls into view.
- Load the Asset: Once visible, dynamically update the CSS or load the image source directly.
For demonstration purposes, let's assume you want to load the background only when the .image--about container becomes visible:
<div class="image-container image--about" data-src="/path/to/ZIZF.gif">
<!-- Content here -->
</div>
The JavaScript Implementation
We will use the Intersection Observer to detect visibility and then dynamically adjust the styles or load the actual resource. This ensures that network requests for large background assets are deferred until they are necessary, greatly improving perceived performance.
document.addEventListener('DOMContentLoaded', () => {
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const target = entry.target;
const imageUrl = target.dataset.src;
// Apply the background only when visible
target.style.backgroundImage = `url('${imageUrl}')`;
// Stop observing once loaded
observer.unobserve(target);
}
});
}, {
rootMargin: '0px',
threshold: 0.1 // Trigger when 10% of the element is visible
});
// Start observing all elements with the class we want to lazy load
document.querySelectorAll('.image-container').forEach(el => {
observer.observe(el);
});
});
Performance and Backend Considerations
This client-side approach handles the visual lazy loading perfectly. From a backend perspective, when dealing with large assets managed by systems like Laravel, efficiency is paramount. Frameworks like Laravel excel at managing routing and asset delivery, ensuring that when the JavaScript requests /path/to/ZIZF.gif, the file is served efficiently. Proper resource management on the server side, alongside smart client-side loading techniques, forms the backbone of high-performance applications. Thinking about how assets are delivered is just as crucial as how they are displayed, much like ensuring optimized database queries in a robust Laravel application.
By combining the browser's native observation capabilities with targeted JavaScript execution, you effectively defer the load of background images, ensuring that your initial page render is fast and responsive, regardless of the image size or location on the page.
Stefan
SEO engineer and Laravel developer. Building tools to help Laravel applications rank higher in search results.