ESC

Type to search the knowledge base.

picture and srcset

Responsive images in HTML — srcset width descriptors, sizes, art direction with picture/source, and type-based format negotiation.

intermediate3 min read
  • html
  • picture
  • srcset

srcset + sizes let the browser pick a file density/width. <picture> adds art direction and format negotiation. CSS alone cannot choose a smaller download for a smaller layout slot — that’s HTML’s job.

Docs: MDN responsive images, <picture>, srcset.

Width-descriptor srcset

<img
  src="/hero-800.jpg"
  srcset="
    /hero-400.jpg 400w,
    /hero-800.jpg 800w,
    /hero-1200.jpg 1200w
  "
  sizes="(min-width: 48rem) 50vw, 100vw"
  width="1200"
  height="675"
  alt="Team workshop at a whiteboard"
  loading="lazy"
  decoding="async"
/>
  • w descriptors — intrinsic width of each file
  • sizes — the image’s display width in CSS pixels under conditions
  • Browser picks a candidate using viewport, DPR, and sizes

If sizes lies, users get blurry or oversized downloads.

Density descriptors (simpler assets)

<img
  src="/icon.png"
  srcset="/icon.png 1x, /icon@2x.png 2x"
  width="32"
  height="32"
  alt=""
/>

Good for fixed-size icons; less flexible for fluid layouts than w + sizes.

Art direction with picture

<picture>
  <source
    media="(max-width: 40rem)"
    srcset="/hero-mobile.jpg 800w"
    sizes="100vw"
  />
  <source
    media="(min-width: 40.01rem)"
    srcset="/hero-desktop.jpg 1600w"
    sizes="100vw"
  />
  <img
    src="/hero-desktop.jpg"
    width="1600"
    height="900"
    alt="Conference keynote stage"
  />
</picture>

Different crops, not just resolutions — CSS object-fit can’t invent a mobile-specific composition.

Format negotiation

<picture>
  <source type="image/avif" srcset="/photo.avif" />
  <source type="image/webp" srcset="/photo.webp" />
  <img src="/photo.jpg" alt="Product on a desk" width="800" height="600" />
</picture>

First supported type wins; final <img> is required fallback and holds alt/size.

Always keep the img

<picture> without <img> is invalid for providing the image resource. Alt, dimensions, and lazy loading live on the img.

Pair with CSS

img {
  max-width: 100%;
  height: auto;
}

Layout width must match the story you told in sizes.

Interview out-loud

“srcset with w and sizes lets the browser pick a resolution for fluid images. picture handles art direction via media and formats via type. The nested img is mandatory for alt and fallback. Honest sizes matching CSS layout is the usual bug.”

Footguns

  1. Only shipping 2x images and calling it responsive.
  2. sizes="100vw" when the image is a 200px thumbnail.
  3. Forgetting width/height → CLS.
  4. Using picture for format only when a single <img srcset> with type isn’t available — picture is correct for type switching.
  5. Lazy-loading LCP hero images — often should be eager + high fetch priority.

Debugging wrong candidate

  1. Network panel → img request → which file downloaded?
  2. Compare to computed layout width × DPR.
  3. Fix sizes first, assets second.
  4. Confirm server returns correct Content-Type and dimensions.
<!-- Thumbnail in a 3-column grid -->
<img
  src="/t-400.jpg"
  srcset="/t-200.jpg 200w, /t-400.jpg 400w, /t-800.jpg 800w"
  sizes="(min-width: 64rem) 20vw, (min-width: 40rem) 33vw, 100vw"
  width="800"
  height="800"
  alt=""
  loading="lazy"
/>

Tune sizes whenever the grid breakpoints change.

CMS and CDNs

Image CDNs (imgix, Cloudinary, etc.) can generate width variants on the fly. Still emit correct srcset/sizes in HTML — the CDN does not know your layout. Prefer a small set of widths (e.g. 400/800/1200/1600) over infinite variants to keep caches hot. Avoid shipping both art-direction crops and unused full-frame assets on every page.

Hero with format + width

<picture>
  <source
    type="image/avif"
    srcset="/h-800.avif 800w, /h-1200.avif 1200w"
    sizes="100vw"
  />
  <source
    type="image/webp"
    srcset="/h-800.webp 800w, /h-1200.webp 1200w"
    sizes="100vw"
  />
  <img
    src="/h-1200.jpg"
    srcset="/h-800.jpg 800w, /h-1200.jpg 1200w"
    sizes="100vw"
    width="1200"
    height="675"
    alt="…"
    fetchpriority="high"
  />
</picture>

Combine type negotiation with width selection carefully — each source can carry its own srcset. Keep descriptors consistent across formats.

Further reading

Related guides