The three vitals, in one sentence each
- LCP — Largest Contentful Paint: how long until the biggest above-the-fold thing draws. Target <2.5 s.
- CLS — Cumulative Layout Shift: how much your layout jumps after first paint. Target <0.1.
- INP — Interaction to Next Paint (replaced FID in 2024): how long the page takes to respond to clicks. Target <200 ms.
Images can hurt all three. The biggest leverage is on LCP.
Why LCP loves smaller images
The hero image is the LCP element on a huge fraction of pages. The browser can only paint it after it's downloaded and decoded. Cut its size, and you cut its download time and decode time both. WebP is a 50–70% file-size win on most photographic heros, and it decodes faster than equivalent-quality JPEGs in modern engines.
Where to start (in order)
- Convert your hero image to WebP. One file. Five minutes. Often takes LCP from amber to green by itself.
- Set
widthandheighton every<img>. Browsers reserve space and skip layout-shift entirely. Good for CLS too. - Preload the LCP image with
<link rel="preload" as="image" href="/hero.webp" fetchpriority="high">in the head. - Lazy-load below-the-fold images with
loading="lazy". - Convert the rest of your images. Use the in-browser converter or a batch script.
Common mistakes
Lazy-loading the LCP image
Don't. loading="lazy" on your hero will delay the very thing LCP measures. Use fetchpriority="high" instead.
Using the wrong dimensions
A 4000-px-wide image displayed in a 600-px-wide column wastes ~95% of the bytes. Resize on export, or serve responsive images with srcset and sizes.
Ignoring fonts
Web fonts can also become the LCP element if your largest text renders before the hero image. font-display: swap + a self-hosted woff2 closes the gap.
What WebP does not fix
- JavaScript bloat. If your bundle is 1.2 MB minified, image format won't save you.
- Render-blocking CSS. A giant blocking stylesheet delays everything, including your beautiful WebP hero.
- Slow servers / TTFB. If your origin takes a second to send the first byte, you're starting in the hole.
A measurement loop that actually works
- Run Lighthouse on a real page (not localhost — it lies).
- Note the LCP element and its file size in the network panel.
- Apply one fix.
- Re-run. Repeat.
Three or four iterations of this and most pages tip from amber to green. The first iteration is almost always "make the LCP image a WebP."