Home HTML

<picture>, srcset, and responsive images

<picture> with <source> and srcset selects the best image for the viewport, pixel density, and supported format. The replacement for the JavaScript-shimmed responsive-image patterns of 2014–2018.

What <picture> does

<picture> lets the user agent pick a candidate image from a list, by:

  1. Format — modern format (image/avif, image/webp) with a raster fallback for older agents.
  2. Pixel density1x, 2x, 3x candidates per device.
  3. 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:

  1. The first <source> whose media and type predicates pass is chosen.
  2. Within the chosen <source>, the user agent resolves the srcset against current pixel density and the sizes value to compute the layout width, then picks the smallest candidate whose intrinsic width is ≥ the layout width.
  3. If no <source> matches, the <img> and its srcset are 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

FormatCompression vs JPEGCross-engine support
WebP~25–35% smallerAll major engines since 2020.
AVIF~50% smallerAll 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 get high; below-the-fold illustrations get low.
<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

  • alt missing on the <img>. Tools flag as a 1.1.1 Non-text Content failure (Level A).
  • No sizes with width-descriptor srcset. User agent assumes 100vw and over-fetches.
  • <source> without type. The user agent cannot prune formats it does not support; the browser may parse the wrong candidate.
  • No width and height. 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