Back to the Lab

The Lab · Development

AVIF, WebP or JPEG: Picking an Image Format in 2026

AVIF cuts photo file size 30-50% below JPEG but encodes slower

RAXXO Studios 8 min read
TLDR This entry in one minute

Each line jumps to its section

  • AVIF cuts photo file size 30-50% below JPEG but encodes slower
  • WebP is the safe middle ground with 97%+ browser support
  • JPEG stays as the final fallback so nobody gets a broken image
  • The picture element tries each format top to bottom automatically

I shipped a product page last month with a hero photo that weighed 1.4MB as JPEG. Re-encoded as AVIF it dropped to 320KB with no visible loss. That's the whole reason this choice matters, and in 2026 you don't have to pick just one.

Here's how I decide which format to serve, and how I stack all three so a visitor on any browser still sees the picture.

What Each Format Is Actually Good At

JPEG is 30 years old and it still works everywhere. Every browser, every email client, every ancient Android phone. It handles photos well. It falls apart on sharp edges, text, and flat color, where you get those grey smudges around lines. It can't do transparency. For a photograph where support matters more than bytes, it's still fine.

WebP is the one I reach for by default. It does both lossy and lossless, it supports transparency, and it animates. On a typical product photo it lands 25-35% smaller than JPEG at the same visual quality. The encode is fast. The support is basically universal now.

AVIF is the heavy hitter. Based on the AV1 video codec, it crushes file sizes harder than anything else I've tested. That 1.4MB JPEG becoming 320KB wasn't a fluke, 30-50% below JPEG is the normal result. It handles transparency, wide color gamut, and HDR. The catch is encode time. AVIF is slow to compress, sometimes 10-20x slower than WebP for the same image.

So the rough rule I use:

Photos where every byte counts: AVIF first.

UI assets, icons, screenshots with text: WebP, because the encode is quick and the quality holds on sharp edges.

Anything that has to display on hardware I can't predict: keep a JPEG around.

One thing people forget is that quality settings aren't comparable across formats. AVIF quality 50 is not WebP quality 50. I tune each one by eye, or by target file size, not by copying a number across. For a 1600px-wide hero I usually land around AVIF quality 55, WebP quality 78, JPEG quality 82. Those numbers drift per image, but they're my starting point.

Browser Support in 2026 and Why It's Not a Blocker

The support question used to end these debates. It doesn't anymore.

WebP is supported in every current browser and has been for years. If you're only serving WebP with a JPEG fallback, you're covering everyone who's touched a browser update since roughly 2020. No caveats.

AVIF is the newer one, and it's the reason people still hesitate. But Chrome, Firefox, Edge, Safari, and the mobile versions of all of them decode AVIF now. The gaps are old installs and a few embedded webviews. That's a small slice, and it's shrinking every month.

The reason none of this stops me is the fallback chain. I don't have to bet on AVIF support. I serve AVIF to browsers that take it and quietly drop down to WebP, then JPEG, for everyone else. The browser picks the first format it understands. No feature detection in JavaScript, no user-agent sniffing, no broken image icon.

That's the part worth sitting with. You can adopt the newest, smallest format with zero downside, because the fallback is built into HTML itself. The worst case for an old browser is that it gets the JPEG it would have gotten anyway. The best case for a modern browser is a file less than a quarter the size.

I treat performance work the same way I treat reliability work: assume something will fail and make the failure boring. If you want the same mindset applied to retries, Retry With Backoff and Jitter walks through the pattern I copy into every project.

The only real cost of adding AVIF is the encode step at build time, and that's a machine problem, not a user problem. Which brings up the trade I actually think about.

Encode Cost Versus File Size

Smaller files are not free. Somebody's CPU paid for them.

AVIF's compression comes from doing a lot of work up front. On my build machine, encoding a single 2000px photo to AVIF at a good quality setting takes a few seconds. WebP does the same image in a fraction of that. JPEG is near instant. Multiply by a catalog of a few hundred product shots and the AVIF step is suddenly the slowest thing in the build.

I handle this with a cache. I hash the source image plus the encode settings, and if nothing changed I reuse the output. So AVIF only pays its slow encode once per image, not once per build. After the first run, rebuilds skip anything untouched. This is the same caching instinct I use for catalog lookups, which I benchmarked in Binary Search vs Array.includes().

The numbers that make the slow encode worth it: a 10-image gallery at 1.4MB each is 14MB of JPEG. The same gallery in AVIF can come in under 4MB. That's the difference between a page that loads instantly on mobile and one where images pop in a second late while someone's already scrolling past.

I also don't encode every size for every format. I pick two or three widths (say 640, 1280, 1920), and generate AVIF and WebP for each, plus one JPEG fallback per width. That's a manageable fan-out. Going wider than three sizes rarely earns its keep for the kind of pages I build.

If you're generating or upscaling source art before you compress it, the encode step runs on whatever you export. I run a lot of my source images through Magnific for upscaling first, then compress the result into the format stack. Clean source in, small files out.

One honest caveat: AVIF can look worse than WebP at very low file sizes on images with fine grain or film noise. It smooths detail it thinks is unimportant. For a product on a plain background that's invisible. For textured photography, check it with your own eyes before trusting the byte count.

The Fallback Chain I Actually Ship

This is the whole thing in one HTML element. The picture element lets you list sources in order, and the browser uses the first one it supports.


<picture>
  <source srcset="hero.avif" type="image/avif">
  <source srcset="hero.webp" type="image/webp">
  <img src="hero.jpg" alt="Product hero shot" width="1280" height="720">
</picture>

The browser reads top to bottom. If it's AVIF-capable, it takes the first line and stops. If there's no AVIF support but WebP works, it uses the second line instead. Nothing modern at all? It falls through to the plain img, which every browser understands. That img is not optional. It's the thing that guarantees nobody sees a broken image.

A few details I never skip.

Always set width and height on the img. This reserves the space before the image loads so the page doesn't jump around. Layout shift is one of the easiest performance wins and most people leave it on the table.

Always write a real alt. The fallback chain protects the format, the alt protects the meaning when the image itself fails.

For responsive sizes, each source gets its own srcset with the width descriptors, and a sizes attribute so the browser knows how wide the image renders. That gets verbose fast, which is why I generate the whole block from a template rather than writing it by hand. I feed the image name and dimensions in, and the markup comes out with all three formats and all my widths wired up.

I keep that generation logic in the same place as the rest of my asset pipeline, with structured logs so I can see which images got re-encoded and which came from cache. If that sounds useful, Structured Logging I Add on Day One is how I set that up.

The result is one source of truth. I drop in a JPEG or PNG, the build produces the AVIF and WebP variants, caches them, and writes the picture markup. I never touch the fallback chain by hand, so I never get it wrong.

Bottom Line

If you do nothing else, serve WebP with a JPEG fallback. That's a 25-35% size cut on your photos with support you don't have to think about, and it's maybe an hour of pipeline work.

If you want the bigger drop and you've got a build step that can cache, add AVIF as the top of the chain. The picture element means there's no risk: old browsers get the JPEG they'd have gotten anyway, modern ones get a file a third of the size. Just watch textured images by eye, and cache the slow encode so it only runs once.

I'd start with the three-format stack on your heaviest page, measure the load, and roll it out from there. The pattern is the same everywhere, which is the point. I document how I wire these build-time steps into a repeatable setup in the Claude Blueprint if you want the fuller picture of how my pipeline fits together.

Pick the format per use, keep the fallback, and let the browser do the choosing.

This article contains affiliate links. If you sign up through them, I may earn a small commission at no extra cost to you. (Ad)

Get the next entry by mail
One mail when a new entry lands. No spam. Unsubscribe anytime.
RAXXO Studios

Written by

RAXXO Studios

One designer in Berlin, close to twenty years in. I build tools with AI, use them daily, and write down what happened.

Share this entry

X LinkedIn
All entries