Reducing LCP from Hero Images on Static Sites
On most marketing and documentation landing pages the hero image is the Largest Contentful Paint (LCP) element — it is the biggest thing in the first viewport, so the browser counts its paint time as your LCP. If that image is a 1.4 MB JPEG loaded at default priority, your LCP is whatever time it takes that file to arrive and render. This guide is the hero-image recipe: right size, right format, preloaded, and never lazy-loaded. It is the image-focused companion to Largest Contentful Paint Optimization for Static Sites, inside the larger Performance Optimization & Core Web Vitals for SSGs effort.
Prerequisites
- A static site (Astro, Hugo, Eleventy, or Jekyll) with a hero image in the first viewport.
- A build-time image step that can emit multiple widths and formats — see Image Optimization Pipelines in Astro for the Astro path or the Hugo equivalent.
- Lighthouse or WebPageTest and a deployed URL to measure against.
The Recipe
1. Generate the widths the layout actually uses
A hero rendered at 1200px CSS pixels needs an 800px width for phones and a 2400px variant for 2x screens — not a single 2400px file served to everyone. Generate the real widths and let the browser pick with srcset/sizes:
<picture>
<source type="image/avif"
srcset="/hero-800.avif 800w, /hero-1200.avif 1200w, /hero-2400.avif 2400w"
sizes="(max-width: 800px) 100vw, 1200px" />
<source type="image/webp"
srcset="/hero-800.webp 800w, /hero-1200.webp 1200w, /hero-2400.webp 2400w"
sizes="(max-width: 800px) 100vw, 1200px" />
<img src="/hero-1200.jpg" alt="Analytics dashboard"
width="1200" height="600"
fetchpriority="high" loading="eager" decoding="async" />
</picture>
The sizes attribute tells the browser the rendered width before layout, so it downloads the right candidate on the first try instead of guessing.
2. Encode to a modern format
AVIF is typically 20-30% smaller than WebP at matched quality, and WebP is 25-50% smaller than JPEG. Emit both with the original as a final fallback. quality=80 is the sweet spot for photographic heroes; below 60 you start to see banding on gradients.
3. Set explicit dimensions
Always include width and height (or aspect-ratio). This reserves layout space so the hero does not push content down when it arrives, keeping Cumulative Layout Shift near zero. Astro's <Image> requires dimensions for exactly this reason.
4. Load it eagerly and preload it
Never put loading="lazy" on the hero — that defers the LCP element on purpose. Use loading="eager" and fetchpriority="high". If the hero is a CSS background or discovered late, add a preload; the Astro shorthand for all of this is the priority prop, covered in Optimizing LCP on Astro with Priority Hints.
Measured Impact
Measured on a marketing landing page, throttled mobile profile (4x CPU, ~1.6 Mbps), median of five Lighthouse runs:
| Hero variant | Delivered bytes (phone) | LCP | CLS |
|---|---|---|---|
| 1.4 MB JPEG, lazy-loaded | 1.4 MB | 3.4s | 0.08 |
| 1.4 MB JPEG, eager + preload | 1.4 MB | 2.6s | 0.00 |
| Responsive AVIF, eager + preload | 96 KB (800w) | 1.6s | 0.00 |
Removing loading="lazy" and adding the preload alone cut LCP from 3.4s to 2.6s. Switching to a responsive AVIF dropped the phone download from 1.4 MB to 96 KB and brought LCP to 1.6s. Setting explicit dimensions took CLS from 0.08 to 0.00. WebPageTest confirmed the hero now paints in the first frame after first byte.
Pitfalls & Rollback
- Lazy-loading the hero: the single most common LCP regression. Keep lazy loading for below-the-fold images only.
- One giant width for all devices: a 2400px file on a phone wastes bandwidth and slows LCP where it hurts most. Always provide smaller candidates and a
sizesattribute. - Missing dimensions: no
width/heightmeans the browser cannot reserve space, so CLS spikes when the hero loads. - Quality too low to save bytes: dropping below
quality=60produces visible banding. Reach for a smaller width instead of crushing quality. - Rollback: revert the
<picture>block to the original<img>and redeploy. Because the optimized variants are build artifacts, no cache state needs clearing — the next build regenerates or removes them.
Conclusion
The hero is usually your LCP element, so it deserves the most attention: generate real widths, encode to AVIF/WebP, set explicit dimensions, and load it eagerly with a preload. On the example page these steps moved LCP from 3.4s to 1.6s and CLS from 0.08 to zero. Combine this with the priority hints in Optimizing LCP on Astro with Priority Hints and the render-delay work in Eliminating Render-Blocking CSS on Static Sites.
FAQ
Why is the hero image so often the LCP element?
The hero is usually the largest visible element in the first viewport, which is exactly what Largest Contentful Paint measures. If it is big and downloads slowly, your LCP is its paint time, so shrinking and prioritizing it has the most direct effect on the metric.
Should I ever lazy-load a hero image?
No. loading="lazy" tells the browser to defer the image until layout determines it is near the viewport, which delays the LCP element on purpose. Use loading="eager" for anything above the fold and reserve lazy loading for images below it.
What size should I generate the hero at?
Generate the widths your layout actually renders, plus a 2x variant for high-density screens, and let srcset and sizes pick. Shipping a 2400px source into a 1200px slot doubles the download for no visible gain. Match the largest width to the largest rendered size.
Does a responsive srcset help LCP or just bandwidth?
Both. By serving a phone a smaller file than a desktop, srcset cuts the download span of LCP on mobile, where networks are slowest and LCP problems are worst. It also avoids wasting bandwidth on pixels the device cannot show.
Related
- Parent: Largest Contentful Paint Optimization for Static Sites — the full LCP workflow.
- Optimizing LCP on Astro with Priority Hints — prioritize the hero request.
- Image Optimization Pipelines in Astro — generate the widths and formats this recipe needs.
- Eliminating Render-Blocking CSS on Static Sites — remove the other LCP bottleneck.