iKit
Tutorial · 9 min read ·

Serve AVIF, WebP & JPG With One <picture> Tag (2026)

Use one <picture> tag to serve AVIF, WebP, and JPG so every browser gets the smallest image it can decode. Syntax, fallback order, and the mistakes to avoid in 2026.

Serve AVIF, WebP & JPG With One <picture> Tag (2026)

Serve AVIF, WebP, and JPG With One <picture> Tag

You converted your photos to AVIF, shaved 50% off their weight, and then realized a chunk of your visitors get a broken image icon. The fix is one HTML element. The <picture> tag lets you offer AVIF, WebP, and JPG side by side and let each browser pick the smallest file it can actually decode — no JavaScript, no user-agent sniffing, no server logic. Here is exactly how to wire it up and the mistakes that quietly break the fallback.

TL;DR

  • <picture> wraps <source> elements plus one <img>; the browser picks the first source it supports.
  • Order matters: AVIF first, then WebP, then JPG on the <img> fallback.
  • Use type="image/avif" and type="image/webp" so the browser matches without downloading.
  • Put alt, width, height, and loading on the <img>, never on <source>.
  • AVIF covers ~94% of browsers in 2026; WebP and JPG cover the rest.

How the <picture> element picks an image format

The <picture> element is a wrapper. On its own it renders nothing — it needs a child <img> to display, and zero or more <source> elements to offer alternatives. The browser reads the sources in document order, finds the first one it can handle, and rewrites the inner <img> to use that file. If it supports none of them, it just shows the <img>.

The source order is a command, not a suggestion

This is the detail people miss. When you use srcset on a plain <img>, you are giving the browser hints and it makes its own call about which file is best for the screen. With <picture>, the <source> list is evaluated strictly top to bottom and the browser commits to the first match. As the web.dev guide from the Chrome team puts it, the <source> element is more like a command than a suggestion — web.dev's responsive design course spells out this difference directly. Practically: whatever format you want browsers to prefer goes first.

Where the type attribute does the matching

Each <source> carries a type attribute holding a MIME type — image/avif, image/webp, image/jpeg. The browser checks whether it can decode that type before requesting the file, so it never downloads an AVIF it cannot render. Per MDN's <picture> reference, the user agent considers each source's type, media, and srcset attributes to choose the best match. Get the MIME string wrong (a stray image/avif+ or image/jpg instead of image/jpeg) and that source is silently skipped.

Why the <img> tag is required, not optional

The inner <img> is the real element — it is what shows up in the DOM, what screen readers announce, and what older browsers fall back to. Drop it and the <picture> displays nothing at all. It also owns the universally supported format, which is why the JPG (or PNG) goes here rather than in a <source>. Everything that describes the rendered image — alt, width, height, loading, decoding — lives on this <img>.

A useful mental model: treat <picture> and its <source> children as routing logic that the browser runs at parse time, and treat the <img> as the destination. The sources never render anything themselves; they only redirect the <img> to a better file when one is available. That is why you can add or remove a <source> without touching any of the attributes that affect accessibility or layout — those never move off the <img>.

How to serve AVIF, WebP, and JPG with one tag

Here is the complete pattern. Three files, one element, every browser covered:

<picture>
  <source srcset="hero.avif" type="image/avif">
  <source srcset="hero.webp" type="image/webp">
  <img
    src="hero.jpg"
    alt="Sunrise over the harbour"
    width="1200"
    height="630"
    loading="lazy"
    decoding="async">
</picture>

A Chrome or Safari user gets hero.avif. A browser without AVIF but with WebP gets hero.webp. Anything older gets hero.jpg. You ship modern formats without sacrificing backward compatibility.

The fallback order that gives the smallest file

Modern codecs beat JPEG by a wide margin, so you want browsers reaching for them first. The rule of thumb for photographic content:

  • AVIF first — typically the smallest lossy files, with HDR and wide-gamut support.
  • WebP second — a strict upgrade on JPEG/PNG with broader reach and faster encoding.
  • JPG (or PNG) on the <img> — the universal safety net every browser can read.

The exact savings depend on the image, but for photos AVIF often lands around half the size of an equivalent JPEG, with WebP somewhere in between. If you need the format characteristics in detail, MDN's image file type and format guide covers transparency, animation, and compression mode per format.

Putting width, height, and alt in the right place

Always set width and height on the <img>. The browser uses them to compute the aspect ratio and reserve space, which prevents the layout shift that tanks your Cumulative Layout Shift score. The alt text also goes on the <img> and only there — and remember it has to describe the image regardless of which source loaded, since you cannot change alt per format.

<img
  src="chart.jpg"
  alt="Q2 revenue up 18% over Q1"
  width="800"
  height="450">

Lazy loading and the LCP image exception

Add loading="lazy" to below-the-fold images so they only download when scrolled near. But do not lazy-load your Largest Contentful Paint image — usually the hero. Lazy-loading it delays the very pixel Google measures for LCP. For above-the-fold images use loading="eager" (the default) and consider fetchpriority="high".

Do all browsers support AVIF in 2026?

Short answer: nearly all of them, but not quite enough to drop the fallback. That gap is the entire reason <picture> exists.

Current AVIF browser support

AVIF decoding shipped in Chrome 85 (2020), Firefox 113 (2023), Safari 16.4 (2023), and Edge 121 (2024). By early 2026 that adds up to roughly 94% of global users, and AVIF is on track to reach Baseline Widely Available status during 2026 according to the web-features AVIF entry. The holdouts are people on older iOS versions, legacy in-app browsers, and some locked-down corporate Windows builds.

That 94% is high enough to make AVIF your default lossy format, but not high enough to ship it bare on an <img src="hero.avif">. The difference between 94% and a graceful fallback is a handful of users staring at a broken-image icon on the most important visual on the page — and they are disproportionately on exactly the constrained, slow devices that benefit most from a smaller fallback file. The whole point of the three-tier <picture> is that you never have to gamble on that last few percent.

Format First Chrome First Safari
WebP 32 (2014) 14 (2020)
AVIF 85 (2020) 16.4 (2023)

Why WebP is still worth the middle slot

If AVIF already covers 94%, why keep WebP at all? Because that middle 5–6% is real traffic, and WebP is essentially free coverage — it has been supported even longer than AVIF and produces files far smaller than JPEG. The WebP <source> catches browsers that have WebP but not AVIF, so the JPEG fallback is only ever served to genuinely old clients. Three formats, three tiers of coverage, one tag.

Generating the three files without a server (imgconverter)

You need each image in all three formats. You do not need a build pipeline or an upload to do it. iKit's Image Format Converter runs entirely in your browser — drop a JPG in, export AVIF and WebP, and nothing ever leaves your machine. For a folder of images, the Image Compressor handles JPG, PNG, and WebP in batch and zips the output, and the Image Resizer generates the dimension variants if you also serve responsive sizes.

Common <picture> mistakes that break the fallback

The element is forgiving in one bad way: a broken <source> fails silently. Here are the errors that cost people their AVIF savings.

Putting type or src on the wrong element

<source> uses srcset, not src — a src attribute on a <source> is ignored. The <img> uses src, not srcset (unless you are also doing responsive widths). And type belongs on the <source>, never on the <img>. Mixing these up is the single most common reason a fallback chain quietly collapses to the JPEG for everyone.

Forgetting the server Content-Type / MIME type

The browser picks AVIF based on the type attribute, but the server still has to serve the file with a matching Content-Type: image/avif header. If your server returns application/octet-stream for .avif files, some browsers refuse to render them. Check your web server's MIME map and add image/avif and image/webp if they are missing.

Combining formats with responsive sizes

You can do format switching and resolution switching at once. Add srcset width descriptors and a sizes attribute to each <source>:

<picture>
  <source
    type="image/avif"
    srcset="hero-800.avif 800w,
            hero-1600.avif 1600w"
    sizes="(min-width: 60em) 50vw, 100vw">
  <source
    type="image/webp"
    srcset="hero-800.webp 800w,
            hero-1600.webp 1600w"
    sizes="(min-width: 60em) 50vw, 100vw">
  <img src="hero-800.jpg" alt="Sunrise over the harbour"
       width="800" height="420" loading="lazy">
</picture>

Keep the sizes value identical across sources so the browser's width math is consistent no matter which format it lands on. If you only need format switching, leave srcset as a single file and skip sizes entirely.

References

Related on iKit

Related posts