Images are the single largest chunk of bytes on most web pages, and image optimization is the fastest route to a page that feels fast. According to the HTTP Archive, images account for roughly half the total page weight on a median mobile page, and web.dev consistently names oversized images as one of the top causes of poor LCP. Get images right and Largest Contentful Paint drops, Core Web Vitals turn green, and bandwidth bills shrink. This guide covers the four levers that actually move the needle: format, compression, responsive delivery, and load timing.

Why image weight dominates page load

Largest Contentful Paint (LCP), one of the three Core Web Vitals (alongside INP and CLS), measures when the largest visible element finishes rendering. On hero-driven layouts that element is almost always an image. web.dev’s guidance is blunt: serve an LCP image that is too large, too slow, or unoptimized, and your LCP crosses the 2.5-second threshold into “needs improvement” territory.

The cost stacks. A 1.8 MB hero photo served to a phone on a throttled 3G connection takes seconds to arrive, blocks nothing else visually but pushes the moment the user sees anything meaningful well past when they start to leave. Cumulative Layout Shift (CLS) compounds this when an image loads without explicit width and height — the browser reserves no space, content jumps when the file finally arrives, and CLS scores rise. Image optimization is not a cosmetic concern; it is the line between a page that feels instant and one that feels broken.

Formats: pick by content type

The format you choose should match what is in the image, not what your camera happened to produce.

  • AVIF — best ratio of quality to byte size, supported in all modern browsers (Chrome, Firefox, Safari 16.4+). Use it as your first-choice photo format.
  • WebP — the universal fallback. Older than AVIF, slightly larger at equivalent quality, supported everywhere that matters.
  • JPEG — still the legacy fallback for browsers that reject both. Use it behind <picture> for the long tail.
  • PNG — right for graphics with sharp edges, text, or transparency that must stay lossless. Large for photos; do not use it for photos.
  • SVG — the correct choice for logos, icons, and illustrations. Resolution-independent, tiny, and styleable with CSS. Inline it when you can.

A practical build pipeline serves AVIF with a WebP fallback via the <picture> element, and a JPEG as the final fallback. That covers essentially every visitor.

Compression: set a quality floor

Two kinds of compression apply to web images. Lossless compression (PNG, lossless WebP) preserves every pixel but saves little on photos. Lossy compression (JPEG, lossy WebP, AVIF) discards detail the eye barely notices and produces dramatically smaller files.

Pick a quality floor and enforce it in your build. For photos, q=80 (or the AVIF equivalent, often around q=60 because AVIF’s scale differs) is a sane default — visually indistinguishable from the source for most subjects, and roughly 30 to 50 percent smaller than q=90. Push lower for thumbnails and background images where detail matters less. Never serve a q=100 photo on the public web; the byte cost is real and the visual gain is imaginary.

If you are not ready to script a build pipeline, run individual files through an Image Compressor to find the floor for each asset by eye.

Responsive images with srcset and sizes

Shipping one 2400px-wide file to every device is the most common mistake. A phone rendering at 375 CSS pixels does not need the same bytes as a 1440px desktop. srcset lets the browser pick.

<img
  src="hero-1600.jpg"
  srcset="
    hero-480.jpg   480w,
    hero-800.jpg   800w,
    hero-1200.jpg 1200w,
    hero-1600.jpg 1600w"
  sizes="(max-width: 600px) 100vw, (max-width: 1200px) 50vw, 800px"
  width="1600"
  height="900"
  alt="A coastline at sunrise"
  fetchpriority="high"
  decoding="async">

Three things to notice. First, the width and height attributes reserve the correct box before the image arrives, which eliminates layout shift. Second, sizes tells the browser the rendered width at each breakpoint, so it can choose the smallest file that still looks crisp — without sizes the browser assumes the image is 100vw wide and over-downloads. Third, generating each variant is a build-time job; an Image Resizer is the manual equivalent when you do not have one wired into your pipeline.

Lazy loading and the LCP hint

Two attributes do most of the work. loading="lazy" defers offscreen images until the user scrolls near them, which keeps the network clear for content above the fold. decoding="async" hands decoding off the main thread so the image does not jank the UI when it arrives.

For the LCP image specifically, do the opposite: mark it fetchpriority="high" and leave loading at its default of eager. The LCP image is the one thing the user is staring at; it should jump the queue. Every hero image below the fold, decorative asset, and gallery thumbnail should be loading="lazy".

A simple rule: one fetchpriority="high" image per page, everything else lazy. If you find yourself flagging two images as high priority, neither is really the LCP.

Tooling

For one-off work without a build step, the tools below cover the common cases.

  • Image Compressor — squeeze an existing JPEG, PNG, or WebP closer to its quality floor without changing dimensions.
  • Image Resizer — produce the width variants that srcset needs, from a single source file.
  • Image Format Converter — turn a folder of PNGs into WebP or AVIF, or modernize a JPEG collection.

In a real build pipeline these jobs are automated by sharp, squoosh, or your framework’s image component, but the underlying decisions — format, quality, widths — are the same.

FAQ

Should I use AVIF, WebP, or both?

Both, via the <picture> element. AVIF gives the best compression, but WebP has wider support among older devices. List AVIF first, WebP second, and a JPEG as the final <img> fallback. The browser picks the first one it understands.

What quality setting should I use for photos?

Start at q=80 for JPEG and lossy WebP, and around q=60 for AVIF — the scales are not the same. Compare against the source at the rendered size, not full-screen, and drop lower until you notice, then back off one step. Background and thumbnail images can usually go 10 to 20 points lower.

Does loading="lazy" help the LCP image?

No, and applied to the LCP image it actively hurts. Lazy-loading the hero pushes its download request later in the page lifecycle, which raises LCP. Reserve loading="lazy" for images below the fold, and give the LCP image fetchpriority="high" instead.

Summary

The highest-leverage levers, in order: serve a modern format (AVIF with a WebP fallback), set a real quality floor (q=80 for photos, lower where detail does not matter), deliver responsive widths through srcset and sizes so devices get only the bytes they need, and get load timing right with loading="lazy" on everything except the LCP image. Nail those four and your page weight drops, your LCP drops with it, and Core Web Vitals stop being a fire drill.