Lazy-loading images is one of the most commonly recommended performance optimizations. It is also one of the most commonly misapplied. When you lazy-load your hero image, the image that is almost always the largest visible element on the page, you are actively hurting your Largest Contentful Paint (LCP) score.
LCP measures when the biggest visible content element finishes rendering. On most pages, that element is the hero image. When the browser encounters a lazy-loaded image, it does not start downloading it until the image enters the viewport. For a hero image, the image is already in the viewport on page load. But because the lazy-loading attribute tells the browser to wait, it waits. Then it starts downloading. Then it renders. By the time it appears, your LCP has ballooned.
How lazy-loading is supposed to work
Lazy-loading is designed for images the user has not scrolled to yet. When you have a long page with 20 images, loading all 20 on initial page load wastes bandwidth and delays the content the user actually sees.
By adding loading="lazy" to below-the-fold images, the browser skips them during initial load. It only fetches them as the user scrolls down and the images approach the viewport. This saves bandwidth, reduces initial load time, and improves the metrics that matter for the content the user sees first.
This is smart optimization when applied correctly. The mistake happens when it is applied globally, to every image on the page, including the one that matters most.
Why it gets applied wrong
The problem is almost always one of these three scenarios:
The CMS applies it globally. WordPress plugins like WP Rocket, Autoptimize, and even the WordPress core now add lazy-loading to every image by default. Unless you explicitly exclude your hero image, it gets the same loading="lazy" attribute as the image in your footer.
The builder applies it by default. In some Webflow configurations, image elements default to lazy-loading. Builders who do not check the setting end up with a lazy-loaded hero image without realizing it.
A developer blanket-applies it. A common approach is adding loading="lazy" to all <img> tags via a script or template function. It is faster than evaluating each image individually. But it catches the hero image in the sweep.
In each case, nobody intentionally lazy-loads the hero. It happens because the optimization is applied without considering which images are above the fold and which are below.
Want a website that turns visitors into customers, not just compliments?
Book a 15-min introThe LCP impact in real numbers
The difference between an eagerly loaded hero image and a lazy-loaded one is often 1-3 seconds of LCP delay. That is the difference between a "good" LCP (under 2.5 seconds) and a "poor" one (over 4 seconds).
Here is what happens in the browser when the hero image is lazy-loaded:
- The browser starts parsing the HTML.
- It encounters the hero image tag with
loading="lazy". - It skips the image download because the lazy-loading mechanism has not yet confirmed the image is in the viewport.
- The page renders without the hero image.
- JavaScript fires, detects the image is in the viewport, and triggers the download.
- The image downloads, decodes, and renders.
- LCP fires at this point, which is now several seconds after the page started loading.
Compare that to an eagerly loaded hero image:
- The browser starts parsing the HTML.
- It encounters the hero image tag with
loading="eager"(or no loading attribute, which defaults to eager). - It immediately starts downloading the image.
- The image renders as soon as it downloads.
- LCP fires early because the image was prioritized from the start.
The difference is step 3 versus step 5. Eager loading starts the download immediately. Lazy-loading waits for a viewport intersection check that adds unnecessary delay for content that is already visible.
How to fix it
Step 1: Identify your LCP element. Run your page through PageSpeed Insights. In the diagnostics section, it tells you exactly which element is the LCP. On most pages, it is the hero image or a large background image.
Step 2: Set that element to load eagerly. The implementation depends on your platform:
- Webflow: Select the image element, open settings, and change the loading attribute to "Eager" instead of "Lazy" or "Auto."
- WordPress: Exclude the hero image from your lazy-loading plugin's scope. Most plugins have a way to exclude specific images by class, ID, or position. WordPress core lazy-loading can be filtered with
wp_lazy_loading_enabled. - Custom code: Ensure the hero image tag has
loading="eager"or no loading attribute at all. Also addfetchpriority="high"to tell the browser this image is critical.
Step 3: Keep lazy-loading on everything else. The optimization is still valuable for below-the-fold content. Just do not apply it to images visible on initial page load.
The fetchpriority attribute
There is an additional attribute worth knowing: fetchpriority="high". Adding this to your hero image tells the browser to prioritize downloading it over other resources. Combined with eager loading, it ensures your LCP image gets downloaded as early as possible.
The syntax is simple:
<img src="hero.webp" loading="eager" fetchpriority="high" alt="Description">
This combination, eager loading plus high fetch priority, gives your hero image the best possible chance of rendering fast. It is the opposite of what lazy-loading does, and it is exactly what you want for the single most important visual element on your page.
Background images need attention too
CSS background images are not affected by the HTML loading attribute. They load when the CSS is parsed, which can vary depending on whether the stylesheet is render-blocking or deferred.
If your hero uses a CSS background image, ensure the image is referenced in a render-blocking stylesheet so it loads early. If you are loading the image via JavaScript (some sliders and parallax plugins do this), the delay can be even worse than lazy-loading because the JS has to execute before the image even starts downloading.
For hero sections, I generally recommend using an <img> tag with eager loading and high fetch priority instead of a CSS background image. It gives you more control over loading behavior and is easier to optimize for LCP.
The audit you should run right now
Open your site in an incognito window. Right-click your hero image and inspect it. Check the loading attribute. If it says lazy, you have found your LCP problem.
Then check every other image on the page. Everything above the fold should be eager. Everything below should be lazy. That simple rule, applied consistently, is worth more than most performance plugins you could install.
If your PageSpeed score is being dragged down by LCP and you are not sure what is causing it, that is the kind of focused speed audit I run on Webflow and custom sites. The fix is usually simpler than the diagnosis.