Tags: web-dev concept

Modern Image Formats

Date: 2026-08-17


AVIF and WebP against JPEG and PNG. The saving is large and mostly free, the fallback pattern is one HTML element, and the mistake worth avoiding is treating format as the main lever — serving a correctly-sized JPEG beats serving an oversized AVIF every time.


Modern image formats are WebP and AVIF — newer codecs with better compression than JPEG and PNG, served to browsers that support them with a fallback for those that don’t.

What each is for

JPEGPNGWebPAVIF
CompressionLossyLosslessBothBoth
TransparencyNoYesYesYes
AnimationNoNoYesYes
Typical size vs JPEG—much larger~25–35% smaller~40–50% smaller
Encode speedFastFastModerateSlow
Best atPhotographsFlat colour, text, logosGeneral replacementPhotographs, gradients
Weak atFlat colour, sharp edgesPhotographs—Very small images; fine detail at low quality

AVIF’s weakness is worth knowing: at aggressive quality settings it smooths fine detail — fabric texture, hair, product grain — in a way JPEG doesn’t. For a retailer selling on texture, compare at your actual quality setting rather than trusting the file-size figure.

PNG is still correct for flat-colour graphics with hard edges — logos, icons, screenshots with text. Lossy formats put visible artefacts around sharp boundaries. Though for most of those cases, SVG is smaller again and scales.

The fallback pattern

One element, ordered best-first. The browser takes the first type it supports and ignores the rest.

<picture>
  <source srcset="/hero.avif" type="image/avif">
  <source srcset="/hero.webp" type="image/webp">
  <img src="/hero.jpg" alt="Navy wool overcoat, front view"
       width="800" height="1000" fetchpriority="high">
</picture>

The <img> is mandatory and does the real work — it carries the alt, the dimensions, the loading attributes and the fallback source. A <picture> without an <img> renders nothing.

Order matters. The browser picks the first supported type in document order, not the smallest. AVIF before WebP before JPEG.

Combined with responsive sizing, which is the more important lever:

<picture>
  <source type="image/avif"
          srcset="/hero-400.avif 400w, /hero-800.avif 800w, /hero-1600.avif 1600w"
          sizes="(max-width: 600px) 100vw, 50vw">
  <source type="image/webp"
          srcset="/hero-400.webp 400w, /hero-800.webp 800w, /hero-1600.webp 1600w"
          sizes="(max-width: 600px) 100vw, 50vw">
  <img src="/hero-800.jpg" alt="…" width="800" height="1000">
</picture>

That’s verbose, which is the argument for generating it rather than hand-writing it — see below.

Content negotiation, the alternative

Instead of <picture>, serve the best format from one URL based on the request’s Accept header:

GET /hero.jpg
Accept: image/avif,image/webp,image/*,*/*

→ server or CDN returns AVIF bytes at the same URL
→ Vary: Accept        ← REQUIRED, or caches serve the wrong format
<picture>                            CONTENT NEGOTIATION

verbose markup                       one clean <img src>
no cache-key complexity              needs Vary: Accept, and a CDN
                                       that handles it correctly
works with a static host             needs an image service or CDN feature
explicit and debuggable              opaque — hard to tell what was served

Most teams end up with content negotiation, because it’s what image CDNs and framework image components do by default. The Vary: Accept requirement is the thing that breaks when it’s built by hand — CDN Caching, Compression.

Automate it

Hand-managing four formats at three widths means twelve files per image, and it won’t be maintained.

  • A framework image component or an image CDN handles format, sizing, srcset and lazy loading from one source file. This is the right default for almost everyone
  • Encode from the original, not from a JPEG. Re-encoding a lossy file bakes its artefacts into the new one
  • Set quality per format. The scales aren’t comparable — matching quality numbers across encoders produces mismatched results, so tune each by eye once and reuse
  • Check the output is actually smaller. AVIF on a small flat-colour image can exceed the PNG. A build step that keeps whichever is smaller is a few lines and prevents this

Where format isn’t the problem

Serving a 2400px image into a 400px slot wastes far more than any format choice recovers. Dimensions first, format second — Image Optimisation.

The full order of return on a retail page:

1  correct dimensions + responsive srcset     often 60–80% saving
2  modern format                              a further 25–50%
3  quality tuning                             10–20%
4  lazy loading below the fold                doesn't shrink bytes,
                                              moves them off the critical path

And none of it helps if the LCP image is lazy-loaded, which is the self-inflicted wound that undoes the whole exercise — Lazy Loading, Largest Contentful Paint.

Where it interacts

  • Image Optimisation — the four levers in full, of which this is the second
  • Priority Hints — fetchpriority="high" on the <img> inside the <picture>, not on the <source>
  • Cumulative Layout Shift — width and height on the <img> are what reserve the space, regardless of format
  • Video and Media — animated content is nearly always better as a video than as an animated image format