To implement image lazy loading in HTML, simply add loading="lazy" to any <img> tag: the browser will only download that image when it is about to enter the viewport, with no JavaScript required. It is the best effort-to-impact performance change available for most websites today.
This guide covers how to use it correctly, which mistakes to avoid, and when to complement it with additional techniques.
What Is Lazy Loading and Why Does It Matter?
Lazy loading defers the download of resources the user cannot yet see. For images, this means they are only downloaded as the user scrolls and the image is about to appear in the viewport.
The benefits are immediate and measurable:
- Lighter initial payload — the browser downloads only the images visible on first load, reducing transferred data by tens or hundreds of KB.
- Better LCP (Largest Contentful Paint) — less bandwidth competition means the hero image or main content loads faster.
- Data savings for the user — especially important on mobile with limited connections; many visitors never scroll to the bottom.
- Lower load on image server or CDN — only images someone actually views get served.
The Native Method: the loading="lazy" Attribute
Since 2019, modern browsers support native lazy loading via the HTML loading attribute. No external libraries or JavaScript needed.
<img
src="product-photo.jpg"
alt="Red athletic shoes size 9"
width="800"
height="600"
loading="lazy"
>
That is all it takes. The attribute accepts three values:
lazy— deferred loading. Use this on all images that are not visible when the page loads.eager— immediate loading (the default behavior without the attribute). Use this for hero images or logos.auto— lets the browser decide (usually equivalent to eager).
Browser Compatibility
Support covers more than 95% of global users (Chrome 76+, Firefox 75+, Safari 15.4+, Edge 79+). For browsers without support, the image simply loads immediately — no negative effect, just no optimization.
Critical Rule: Never Use loading="lazy" on Above-the-Fold Images
The most common — and most damaging — mistake is applying loading="lazy" to the main image visible without scrolling (the hero, large logo, first product image).
If that image has loading="lazy", the browser deliberately delays it, which can hurt LCP by 500 ms or more. The rule is:
- First visible image on desktop and mobile →
loading="eager"(or no attribute). - Everything else →
loading="lazy".
Also, always include width and height attributes on lazy-loaded images. Without them, the browser cannot reserve space and the layout shifts as each image loads, causing Cumulative Layout Shift (CLS).
Lazy Loading for Iframes and Videos
The same attribute works for <iframe> elements, which is especially useful for heavy YouTube embeds or Google Maps:
<iframe
src="https://www.youtube.com/embed/VIDEO_ID"
title="Product demo"
width="560"
height="315"
loading="lazy"
allowfullscreen
></iframe>
A YouTube iframe loads dozens of scripts and resources. With loading="lazy", all of that is deferred until the user scrolls to the video.
Advanced Techniques: Intersection Observer for Full Control
When you need more control — for example, loading images in dynamic carousels, AJAX-generated content, or very old browsers — the native JavaScript Intersection Observer API is the right solution.
// HTML: use data-src instead of src
// <img data-src="photo.jpg" alt="..." class="lazy-img">
const images = document.querySelectorAll('img.lazy-img');
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.classList.remove('lazy-img');
observer.unobserve(img);
}
});
}, { rootMargin: '200px' });
images.forEach(img => observer.observe(img));
The rootMargin: '200px' parameter starts loading 200 px before the image enters the screen, preventing the user from seeing a blank space while waiting.
To implement these techniques in your stack without errors and with real performance impact, the team at elenlace.com offers turnkey audits and optimizations.
Lazy Loading in WordPress and CMS Platforms
If you use WordPress, the good news is that since version 5.5 (August 2020), WordPress automatically adds loading="lazy" to all images except the first one in the content.
- Do you need to do anything? In most cases, no. Just verify that your template's hero image does not have the attribute.
- Plugins like WP Rocket or LiteSpeed Cache offer additional lazy loading for images in widgets and CSS background images, which the native HTML attribute cannot cover.
- For CSS background images, you need JavaScript or a plugin, since
loadingdoes not apply to CSS properties.
Explore more optimization techniques in our web performance articles.
Key Takeaways
- Adding
loading="lazy"to off-screen images is the fastest performance change to implement, with immediate impact on load time. - Never apply lazy loading to the hero image — it will hurt your LCP and Core Web Vitals score.
- Always include
widthandheightto prevent Layout Shift (CLS). - Native support covers over 95% of users; Intersection Observer covers the rest and advanced use cases.
- WordPress 5.5+ does it automatically; complement with a cache plugin to cover background images.
<iframe>elements also acceptloading="lazy"— use it on YouTube and Google Maps embeds.
Want to go further and bring your site to top-tier performance? The team at elenlace.com runs complete Core Web Vitals audits and handles all optimizations for you — reach out and get started today.
FAQ
Does native lazy loading work in all browsers?
Yes, in over 95% of current browsers. Safari has supported it since version 15.4 (2022). In browsers without support, the image simply loads immediately as always — no negative effect.
Does lazy loading affect SEO or Googlebot crawling?
No. Googlebot indexes images with loading="lazy" normally, as it simulates scrolling during crawling. In fact, improving LCP through lazy loading benefits your SEO.
Can I use lazy loading on CSS background images?
The HTML loading="lazy" attribute does not apply to background-image in CSS. To defer background images you need JavaScript (Intersection Observer) or a plugin like WP Rocket or LiteSpeed Cache, which include this functionality.
How many images should I mark with loading="lazy"?
All of them except the first image visible on screen (the hero or featured image). If you have a carousel above the fold, the first slide should be eager; the remaining slides should be lazy.
Further reading
Other providers and guides worth comparing: