DEV Community

Cover image for Image Optimisation Strategies for Better LCP Scores
Apogee Watcher
Apogee Watcher

Posted on • Originally published at apogeewatcher.com

Image Optimisation Strategies for Better LCP Scores

On many marketing and product pages, Largest Contentful Paint (LCP) is not abstract. It is a hero photograph, a product shot, or a full-width banner. The metric tracks when that largest visible element finishes rendering; if the element is an image, your optimisation work is mostly bytes, dimensions, and discovery order—not another round of “general speed tips”.

This guide assumes you already know what LCP measures. If you need the full picture first, read What Are Core Web Vitals? A Practical Guide for 2026 and LCP, INP, CLS: What Each Core Web Vital Means and How to Fix It. Here we go deep on image-specific strategies that move LCP toward the “good” band (≤ 2.5 seconds in the field), and how to pair them with performance budgets so improvements stick.

Start by identifying the real LCP element

You cannot optimise “the page” in the abstract. LCP is tied to one element in the viewport. In PageSpeed Insights or Lighthouse, open the diagnostics and note which node is reported as LCP—often an <img>, sometimes a text block or a background.

If the tool points at an image:

  • Confirm the URL you are actually serving (CDN vs origin, srcset winner, and any CMS transforms).
  • Check the file size after compression. A 2.5 MB hero on a 360 px wide phone viewport is a sizing problem first, not a format problem.
  • Trace load order: is something else blocking discovery (late CSS, client-rendered markup, or a lazy attribute on the hero)?

Skipping this step is how teams ship a perfect WebP pipeline and still fail LCP because the LCP element was a different image—or text—than they assumed.

Pick modern formats and tune quality deliberately

AVIF usually beats WebP on file size at comparable visual quality; WebP still beats most JPEG for photos. The practical approach for 2026:

  • Serve AVIF with WebP or JPEG fallbacks using <picture> or rely on your CDN’s automatic format negotiation if you trust its tests.
  • Avoid shipping a single giant JPEG “because it works everywhere” unless you have measured that the conversion pipeline genuinely cannot run yet.
  • For illustrations with flat colour, SVG or optimised PNG can win; for large photographic heroes, raster formats dominate.

Quality settings are not universal. A quality of 75 in one encoder is not the same as 75 in another. Pick a default (for example AVIF at a sensible quantiser, WebP at 75–80), then visually compare at real display widths. Automated tools help, but a human glance at banding on skies and skin tones still catches regressions.

When you change format, re-measure LCP on the same URL. Lab scores can move for reasons unrelated to user-perceived quality, so keep before/after filmstrips or screenshots for stakeholders.

Match dimensions to rendered size, not to the asset library

LCP often fails because the browser decodes a 4000 px image into a 400 px slot. Responsive design does not mean “one huge master file for all breakpoints”.

  • Export or generate variants at the maximum CSS width they will occupy, per breakpoint, with a small margin for DPR (device pixel ratio). A 2× retina asset should be roughly 2× the CSS pixels, not 5× “for safety”.
  • Strip metadata you do not need; it is wasted bytes on every request.
  • If your CMS offers “automatic resizing”, verify the actual output dimensions in Network, not the checkbox in the admin UI.

If you only do one thing after reading this section: open DevTools → Network, click the LCP image, and compare Intrinsic size (natural width/height) to Rendered size. If the intrinsic side is many times larger than rendered, fix that before touching anything else.

Use srcset and sizes so the browser picks a sane file

Giving the browser a range of widths beats a single src for almost all content images.

  • srcset lists candidate widths or descriptors (480w, 800w, …).
  • sizes tells the browser how wide the image will be in the layout at different viewport widths, so it can pick the right candidate before downloading the wrong one.

Common mistakes:

  • sizes="100vw" on an image that is only half the layout width—so the browser pulls an unnecessarily large file.
  • Omitting sizes when using w descriptors, which can lead to poor selections.
  • Using loading="lazy" on an image that is above the fold and is your LCP element. The browser may defer work you needed immediately.

For a full-width hero, sizes="100vw" is often correct. For a card grid, describe the column width at each breakpoint. MDN’s documentation on responsive images is worth bookmarking for copy-paste patterns you can adapt.

Loading order: preload, priority, and lazy boundaries

Preload the LCP image when you know the URL early in the document:

<link rel="preload" as="image" href="/images/hero-800.avif" type="image/avif">

Enter fullscreen mode Exit fullscreen mode

Use this when the hero URL is stable and not swapped by heavy client-side logic. If the URL only appears after JavaScript runs, preload may fire too late—fix when the URL is known, not only how it is loaded.

fetchpriority="high" on the LCP <img> nudges the browser to fetch that image sooner relative to other images. Use it sparingly (setting high on more than one or two images is usually not helpful) and pair it with not marking that same image as lazy.

Lazy loading belongs on below-the-fold images. For anything in the first screen, omit loading="lazy" or you risk delaying the very resource that defines LCP.

Decoding: decoding="async" can help keep the main thread responsive; test on low-end hardware if you are borderline on LCP.

CSS background images and LCP

Background images set in CSS are not <img> elements. They are still eligible for LCP, but the browser can’t reliably discover the underlying image URL until after CSS is parsed—so you can end up with extra LCP resource load delay. You also lose straightforward alt semantics for critical content.

If your hero is purely decorative, a background can be fine—but you still pay the same byte and timing costs. If the hero carries meaning (product, banner text is not enough), prefer semantic <img> or <picture> so preload and priority hints map cleanly to the resource.

When you must keep a background, preload it explicitly (e.g. link rel="preload" with fetchpriority="high" or a matching Link header) so it starts fetching early, and make sure the CSS/JS that reveals it doesn’t block rendering.

Third-party CDNs and transforms

Image CDNs that resize, reformat, and cache at the edge can shrink time-to-bytes dramatically. When you adopt one:

  • Lock URL parameters (width, quality, format) so marketing edits in the CMS do not silently generate new uncached variants.
  • Watch cache hit ratios after deploys; a “small” config change can bust effective caching.
  • Align transforms with your srcset strategy—duplicating the same logical image under twenty unbounded parameter combinations is a recipe for cache fragmentation.

CMS uploads and the “full size” trap

Many CMS/theme setups default new uploads to full resolution and then display them small. The HTML still references a massive file unless your theme registers proper image sizes and the markup uses them.

If you inherit a WordPress or similar build, check: (1) registered image sizes for hero slots, (2) whether the template uses wp_get_attachment_image with a named size or blindly outputs the original, (3) whether page builders inject full URLs into inline styles. One corrected template often beats dozens of hand-compressed assets nobody uses.

Verify in the lab, then confirm in the field

After changes:

  1. Run PageSpeed Insights (or Lighthouse) on mobile and note LCP and the LCP element breakdown (TTFB, resource load delay, duration, render delay).
  2. Compare field data (CrUX) where available—lab wins do not always match real users on slow networks.
  3. If you use automated monitoring, add or check budgets for LCP on key templates so regressions surface when someone ships a new hero asset.

For a before/after story, WebPageTest filmstrips or Lighthouse’s View Trace help show whether you shortened resource load duration or merely shifted work. If TTFB or render delay still dominates, image tweaks alone will not get you to green.

Document one baseline number (median LCP or Lighthouse LCP) per template so the next redesign has a reference point.

Tie optimisation to budgets and ownership

Image work is easy to undo: a new campaign drops a 4 MB PNG into the hero and nobody notices until Search Console complains. Add a simple budget per template: maximum dimensions, maximum encoded kilobytes, and allowed formats. Our Performance Budget Thresholds Template is a starting point if you do not have internal standards yet.

Assign who approves hero assets in the CMS—often a designer uploads once and the performance contract is forgotten. A short checklist in the handover doc beats a post-launch fire drill.

What to do next

  1. Identify the LCP element on your top templates.
  2. Resize and re-encode; wire srcset/sizes correctly.
  3. Remove lazy loading from above-the-fold heroes; add preload or fetchpriority where appropriate.
  4. Re-test in the lab and watch field metrics after release.

Small, measurable steps beat a sweeping “image audit” that never ships.

FAQ

Is the hero image always the LCP element?

No. LCP is the largest visible element in the viewport; it can be a headline block, a video poster, or another image. Always confirm in your tooling before optimising the wrong asset.

WebP or AVIF first?

Prefer AVIF with a WebP or JPEG fallback for broad support, or use CDN negotiation if you have verified behaviour across browsers you care about.

Does lazy loading hurt LCP?

Lazy-loading your actual LCP element can delay LCP. In practice, omit loading="lazy" for the first-screen hero (and for any image the diagnostics report as LCP).

Do I need a CDN to pass LCP?

Not always, but a CDN often cuts latency and improves repeat visits. If TTFB or download time dominates your LCP breakdown, origin geography and caching deserve attention alongside image bytes.

Top comments (0)