Lazy loading and fetchpriority for images
Two HTML attributes that, used well, greatly improve loading —and used badly, make it worse. This guide explains when to apply each one.
The basic idea
When loading a page, the browser has to decide in which order to download dozens of resources. For images, two attributes let you guide that decision:
loading="lazy": "don't download this image until it's about to be seen".fetchpriority="high": "this image matters, download it as soon as possible".
They complement each other: lazy for what's below the fold and high priority for the main image.
loading="lazy"
<img src="gallery-12.webp" loading="lazy" width="800" height="600" alt="…">
With this attribute, the browser delays the download until the image approaches the viewport. Thresholds are chosen by the browser based on the connection (in Chrome, between 1250 and 2500 px away). It's supported in every modern browser and needs no JavaScript.
Benefits: saves data for visitors who don't scroll and frees bandwidth for what matters first.
Where to use it: galleries, article images below the first screen, thumbnails in long listings, comment avatars, footer logos.
The costliest mistake: lazy on the main image
If the image visible on load (the LCP) has loading="lazy", the browser won't request it until it has computed the page layout, which can delay LCP by several hundred milliseconds. It's one of the most common issues Lighthouse flags.
Many CMSs and plugins add lazy to every image automatically. Make sure the first visible image doesn't get it. WordPress, for example, has skipped the attribute on the first content image since version 5.9, but themes and page builders can bypass that logic.
fetchpriority="high"
<img src="hero.avif" fetchpriority="high" width="1600" height="900" alt="…">
By default, images start at low priority and get boosted once the browser discovers they're in the viewport. fetchpriority="high" skips that wait. It's supported in Chrome, Edge, Safari and Firefox.
Use it on one or two images at most per page: the LCP image and, at most, one other critical image. If everything is a priority, nothing is.
You can also use fetchpriority="low" to demote visible but secondary images, such as hidden carousel slides.
decoding="async"
<img src="photo.webp" decoding="async" …>
It signals that the image can be decoded without blocking other rendering work. The impact is small and browsers already do much of this by default, but it's harmless on most images. ImageZap includes it in the generated code.
Summary by image type
| Image | loading | fetchpriority |
|---|---|---|
| Hero / LCP image | (no attribute) | high |
| Header logo | (no attribute) | (default) |
| Images in the first screen | (no attribute) | (default) |
| Below-the-fold images | lazy | (default) |
| Hidden carousel slides | lazy | low |
JavaScript lazy loading
Before native support, libraries swapped data-src for src using an IntersectionObserver. Today they're rarely needed and have drawbacks: the initial HTML doesn't contain the real URL (worse for discovery) and they depend on JavaScript running. If your site still uses one, consider replacing it with the native attribute.
Frequently asked questions
Does lazy loading affect SEO?
Native lazy loading doesn't: Google renders the page and sees the images. JavaScript solutions that don't put the URL in the HTML can make indexing harder.
Should I lazy-load iframes?
Yes, loading="lazy" also works on <iframe>, which is useful for YouTube videos and embedded maps.
Does fetchpriority replace preload?
No. preload is for resources the browser wouldn't discover early (CSS backgrounds, JS-inserted images). If the image is already in the HTML, fetchpriority is enough.
How many images should load without lazy?
Those that appear in the first screen on mobile and desktop. Usually between one and four.