Getting the LCP Image Right: Priority and Format

4 min read

Đọc bằng tiếng Việt →

When a page is slow to show its main content, the culprit is very often one hero image. Compressing it harder helps, but it is rarely the biggest lever. Largest Contentful Paint (LCP) is a timeline with distinct phases, and the image format is only one of them. This article breaks the timeline down and gives a short list of changes to make, in the order we would try them.

The four phases of LCP

web.dev describes LCP as four consecutive parts that add up with no gaps:

  1. Time to first byte: until the first piece of HTML arrives.
  2. Resource load delay: the wait between that first byte and the moment the browser starts fetching the LCP resource.
  3. Resource load duration: how long the download takes.
  4. Element render delay: the time between the download finishing and the element appearing.

On a well-tuned page, the guide suggests roughly 40 percent goes to TTFB, 40 percent to the download, and under 10 percent each to the two delay phases. It is explicit that these ratios are a guide to relative balance, not fixed targets. The takeaway is useful regardless: the delay phases should be close to zero, so if you see a large gap before the image even starts downloading, no amount of file shrinking will fix it. The good threshold for the metric is 2.5 seconds or less, with anything above 4.0 seconds counted as poor.

Step 1: make the image discoverable

Browsers scan the raw HTML early to find resources worth fetching. If your hero image only appears after JavaScript runs, sits in a data-src attribute waiting for a lazy-loading script, or is a CSS background, that early scan cannot see it and the request starts late. The Core Web Vitals roundup on web.dev cites Web Almanac data showing 35 percent of LCP images had URLs that were not discoverable in the initial HTML, and about 7 percent were hidden behind data-src.

<!-- Easy for the preload scanner to find -->
<img src="/img/hero-1200.avif"
     width="1200" height="600"
     alt="Autumn collection on a wooden table">

If a stylesheet or script is the only thing that references the image, add a preload link for it instead, and give it a high priority.

Step 2: raise priority, and never lazy-load it

Images are not render-blocking and do not get top priority automatically, so a hint helps. Put fetchpriority="high" on the one image you expect to be the LCP element. Use it sparingly: marking several images as high priority dilutes the effect. The opposite applies to images that start off-screen, such as hidden carousel slides, where fetchpriority="low" frees bandwidth.

The classic mistake is leaving loading="lazy" on the hero. Lazy loading makes the browser wait until layout confirms the image is in view, which adds exactly the load delay you are trying to remove. Per the same sources, only a small share of eligible pages use fetchpriority at all, so this is an easy win on many sites.

<img src="/img/hero-1200.avif"
     fetchpriority="high"
     width="1200" height="600"
     alt="Autumn collection on a wooden table">

<img src="/img/below-fold.avif"
     loading="lazy"
     width="600" height="400"
     alt="Detail of stitching">

Step 3: pick the right format and size

Once the request starts on time, the download duration depends on bytes. web.dev’s format guidance is straightforward:

  • Use SVG for logos, icons and simple geometric art.
  • For photographs and screenshots, lossy AVIF or WebP generally compress better than JPEG, with JPEG as the universal fallback.
  • Reserve PNG or lossless WebP for images that need maximum fidelity, and use them sparingly because the files are large.
  • For animation, a video element usually beats GIF or APNG on size.

Offering modern formats with a fallback takes a few lines:

<picture>
  <source type="image/avif" srcset="/img/hero-800.avif 800w, /img/hero-1600.avif 1600w" sizes="100vw">
  <source type="image/webp" srcset="/img/hero-800.webp 800w, /img/hero-1600.webp 1600w" sizes="100vw">
  <img src="/img/hero-1600.jpg" width="1600" height="800" fetchpriority="high" alt="...">
</picture>

Remember that dimensions matter as much as format. The same guide’s worked example shows that doubling the pixel density quadruples the pixel count, so serving a 3x image to a screen that only needs 1x multiplies the work enormously. Responsive srcset and sizes let the browser choose, and explicit width and height attributes reserve space so the layout does not jump.

Step 4: check the server and the origin

Because TTFB is a full phase of the timeline, a slow first response eats into the budget before any image logic matters. The same roundup notes that only 33 percent of HTML requests in the Web Almanac were served through a CDN, and suggests caching static HTML, even briefly. Hosting the key image on the same origin as the page also avoids the cost of opening a new connection.

On Shopify and theme work

Shopify’s theme guidance recommends lazy loading only below-the-fold images, requesting the display size rather than a larger file scaled down in the browser, and using responsive images through the platform’s image tag. Those are the same principles applied to Liquid. When we build or audit storefronts through our services, the hero image is the first thing we check, and our themes ship with that in mind.

Further reading

← All posts