What <picture> does
<picture> lets the user agent pick a candidate image from a
list, by:
- Format — modern format (
image/avif,image/webp) with a raster fallback for older agents. - Pixel density —
1x,2x,3xcandidates per device. - Viewport size — different crops or aspect ratios per breakpoint (art direction).
The element wraps zero or more <source> elements followed by
exactly one <img> element. The <img> is the fallback and the
holder of alt, width, and height.
<picture>
<source type="image/avif"
srcset="hero-480.avif 480w,
hero-960.avif 960w,
hero-1440.avif 1440w"
sizes="(min-width: 768px) 50vw, 100vw">
<source type="image/webp"
srcset="hero-480.webp 480w,
hero-960.webp 960w,
hero-1440.webp 1440w"
sizes="(min-width: 768px) 50vw, 100vw">
<img src="hero-960.jpg"
srcset="hero-480.jpg 480w, hero-960.jpg 960w, hero-1440.jpg 1440w"
sizes="(min-width: 768px) 50vw, 100vw"
alt="A nautical chart of the Hebrides on parchment"
width="960" height="640" loading="lazy" decoding="async">
</picture>
About 75% of the responsive-image bytes saved on the average page come from the format step (AVIF / WebP); about 20% from pixel density; the remainder from breakpoint-specific crops, per Cloudinary’s 2024 image-optimisation report.
How the user agent picks a candidate
The algorithm evaluates <source> elements in document order:
- The first
<source>whosemediaandtypepredicates pass is chosen. - Within the chosen
<source>, the user agent resolves thesrcsetagainst current pixel density and thesizesvalue to compute the layout width, then picks the smallest candidate whose intrinsic width is ≥ the layout width. - If no
<source>matches, the<img>and itssrcsetare used.
The sizes attribute is critical; without it, the user agent
assumes 100vw, which over-fetches on multi-column layouts.
srcset density vs width descriptors
Two grammars exist:
<!-- density descriptors: explicit DPR mapping -->
<img srcset="logo.png 1x, logo@2x.png 2x" alt="">
<!-- width descriptors: with sizes -->
<img srcset="hero-480.jpg 480w, hero-960.jpg 960w"
sizes="(min-width: 768px) 50vw, 100vw" alt="">
Density is appropriate for fixed-size raster images (logos, icons). Width descriptors are appropriate for responsive layout images.
Modern format adoption
| Format | Compression vs JPEG | Cross-engine support |
|---|---|---|
| WebP | ~25–35% smaller | All major engines since 2020. |
| AVIF | ~50% smaller | All major engines since 2024 (Safari 16+). |
| JPEG XL | ~60% smaller (lossless) | Firefox 113+ behind flag; Safari 17+ default; Chromium reverted in 2022. |
Authors encode AVIF first, fall back to WebP, fall back to JPEG. About 80% of HTTP-Archive-tracked sites had at least one WebP image by 2023, and 25% had at least one AVIF by end of 2024.
Lazy loading and decoding
loading="lazy"defers the request until the image is near the viewport. Cross-engine since 2022.decoding="async"lets the user agent decode off the main thread. Cross-engine since 2020.fetchpriority="low|high|auto"(cross-engine since 2024) tunes the network-priority queue. Hero images gethigh; below-the-fold illustrations getlow.
<img src="below-fold.webp" alt="..." loading="lazy"
decoding="async" fetchpriority="low" width="800" height="450">
Accessibility
alt belongs on the <img> only — not on <picture> or
<source>. The text describes the image’s function in context:
- A decorative image:
alt=""(empty, not absent). - A button image:
alt="Close"(the button’s name). - A photo of a chart:
alt="Bar chart: WCAG 2.2 adoption …"plus the data in a<figcaption>or accessible table.
Width and height attributes (or the aspect-ratio CSS property)
prevent layout shift; the LCP gain is on average 12% per
Smashing Magazine’s 2023 image-perf study.
Common pitfalls
altmissing on the<img>. Tools flag as a 1.1.1 Non-text Content failure (Level A).- No
sizeswith width-descriptorsrcset. User agent assumes 100vw and over-fetches. <source>withouttype. The user agent cannot prune formats it does not support; the browser may parse the wrong candidate.- No
widthandheight. Causes Cumulative Layout Shift; the user sees content jump as images load. - AVIF and WebP not generated by the build. The most common
reason
<picture>is “broken in production” is that the build pipeline did not produce the alternative formats.
Cross-engine support
<picture> and srcset reached interop in 2016. AVIF reached
cross-engine in 2024 (Safari 16). The decoding, loading, and
fetchpriority attributes reached interop in 2020, 2022, and 2024
respectively.
caniuse for <picture> reports
99% support; AVIF at 96%, WebP at 99%.
Further reading
- HTML Living Standard, §4.8.3 The picture element.
- Jason Grigsby’s
<picture>and srcset deep-dive remains the most thorough author reference (2015, updated 2023). - The Cloudinary 2024 image report for adoption data.
- Web.dev Optimize CLS with the aspect-ratio trick for layout-shift mitigation.