Lazy loading is a technique in which images are loaded only as they approach the viewport. This reduces the initial amount of data and speeds up page loading. This article explains how to configure lazy loading correctly.
Why use lazy loading
| Benefit | Description |
|---|---|
| Faster initial load | Fewer requests and less data during the first render |
| Saves bandwidth | Images below the fold are not loaded if the user does not scroll |
| Better LCP | Resources are focused on above-the-fold content |
| Less server load | Fewer simultaneous requests |
The effect is especially noticeable on pages with many images (catalogs, galleries, blogs).
Native lazy loading (loading="lazy")
Modern browsers support the loading="lazy" attribute on <img> and <iframe>.
<img src="photo.jpg" alt="Описание" loading="lazy" width="800" height="600">How it works
The browser delays loading an image until it approaches the viewport (with a buffer, for example, 1250px). The exact behavior depends on the browser.
Important: width and height
Specify width and height to prevent content shifts (CLS) while loading:
<img src="photo.jpg" alt="Описание" loading="lazy" width="800" height="600">Without dimensions, the browser does not know the aspect ratio, so the content “jumps” when the image loads.
Browser support
Chrome 76+, Firefox 75+, Safari 15.4+, Edge 79+. In older browsers, the image will load immediately—a safe fallback.
What not to lazy-load
Do not use loading="lazy" for:
- Images above the fold (the LCP element)
- The logo in the header
- The hero image in the first viewport
These images should load immediately. Either omit the loading attribute or use loading="eager" (the default value).
<!-- Hero-изображение — без lazy -->
<img src="hero.jpg" alt="Главный баннер" width="1920" height="1080">
<!-- Контент ниже сгиба — lazy -->
<img src="product-1.jpg" alt="Товар 1" loading="lazy" width="400" height="400">Lazy loading for iframes
<iframe src="https://example.com/embed" loading="lazy" width="600" height="400"></iframe>Useful for embedded videos, maps, and widgets.
JavaScript: Intersection Observer
For custom behavior (for example, a placeholder or a fade-in animation), you can use Intersection Observer:
const images = document.querySelectorAll('img[data-src]');
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src || img.getAttribute('data-src');
img.removeAttribute('data-src');
observer.unobserve(img);
}
});
});
images.forEach(img => imageObserver.observe(img));Markup:
<img data-src="photo.jpg" alt="Описание" width="800" height="600" src="placeholder.jpg">Native loading="lazy" is sufficient for most cases. JavaScript is needed for special requirements (blur-up, custom placeholders).
Lazy loading and SEO
- Content in images is indexed. Lazy loading does not prevent crawling—Google scrolls and loads deferred images.
- Important: do not hide key content in images that load only when the user scrolls. The LCP element should not be lazy-loaded.
Impact on Core Web Vitals
| Metric | Impact |
|---|---|
| LCP | Positive—less competition for bandwidth during the initial load |
| CLS | Neutral when width/height are specified; without them, there is a risk of shifts |
| FID/INP | Neutral or positive—less work during loading |
Check: Web Vitals on reChecker.
Common mistakes
| Mistake | Solution |
|---|---|
| Lazy-loading the LCP image | Remove loading="lazy" from the hero/first viewport |
| No width/height | Add them to prevent CLS |
| Lazy-loading every img indiscriminately | Leave the first 1–2 images without lazy loading |
| data-src with no fallback | If JavaScript is disabled, the image will not load—use noscript with a regular img |
Checklist
| Check | Action |
|---|---|
| LCP image is not lazy-loaded | Check the hero and first viewport |
| Other images use loading="lazy" | Add the attribute |
| All img elements have width and height | Specify them to prevent CLS |
| Iframes load lazily | Add loading="lazy" |
| Test in a browser | Check that images below the fold load when you scroll |
Testing tools
- reChecker image check — analyzes attributes, dimensions, and formats
- reChecker Web Vitals — LCP, CLS, FID
- Chrome DevTools — Network (throttling), disable cache, check loading order
Conclusion
Lazy loading speeds up page loading and reduces bandwidth usage. Use native loading="lazy" for images below the fold, do not apply it to LCP elements, and be sure to specify width/height. Check the results with the image check and Web Vitals on reChecker. Also see image optimization and WebP/AVIF.
Lazy loading for background-image
CSS background-image does not support loading="lazy". Options:
- Use img with loading="lazy" and object-fit to create a background-like visual effect
- Load the background with JavaScript when it enters the viewport (Intersection Observer)
- Do not defer loading of a critical background
Lazy loading and printing
Deferred images may not load when a page is printed. Solution: use an @media print media query to force loading, or warn the user. For most websites, this is not critical.
Lazy loading in carousels and sliders
Carousels often hide images that are outside the current slide. Recommendations:
- Load only the visible image at initialization
- Preload neighboring images on hover or 1 slide before display
- Use loading="lazy" for images in hidden slides (if they are in the DOM)
Frequently asked questions
Does lazy loading affect indexing?
Google scrolls and loads deferred images. The content is indexed. Do not apply lazy loading to the LCP element—it may worsen metrics.
Do images above the fold need lazy loading?
No. Images in the first viewport should load immediately. Lazy loading them is pointless and may harm LCP.
Does loading="lazy" work for iframes?
Yes. The loading="lazy" attribute is supported for iframes. It is useful for embedded videos and widgets.