HTMLResponsive Images (srcset, sizes)

Responsive Images (srcset, sizes)

A single <img> tag with one src forces every device to download the same file — a phone on a slow connection gets the same multi-megabyte image as a 4K desktop monitor. The srcset and sizes attributes let the browser choose the most appropriate image from a list of candidates, based on the device's screen size and pixel density.

This is "resolution switching" — the same image content at different file sizes, not to be confused with <picture>'s "art direction" (different crops or compositions), which is a separate topic.

The Problem srcset Solves

HTML
<!-- Without srcset: everyone downloads the same 2400px-wide image -->
<img src="hero-2400w.jpg" alt="Product hero shot">
Warning
Downloading a 2400px-wide image on a 375px-wide phone screen wastes bandwidth, slows the page down, and can hurt Core Web Vitals (specifically Largest Contentful Paint).
Width Descriptors (w)

The most common form of srcset lists candidate images with a width descriptor — the image's actual intrinsic pixel width, suffixed with w. Combined with sizes, this tells the browser exactly how large the image will be displayed at each viewport width, so it can pick the smallest candidate that is still big enough.

HTML
<img
  src="hero-800w.jpg"
  srcset="
    hero-400w.jpg  400w,
    hero-800w.jpg  800w,
    hero-1200w.jpg 1200w,
    hero-2400w.jpg 2400w
  "
  sizes="(max-width: 600px) 100vw, (max-width: 1200px) 50vw, 800px"
  alt="Product hero shot"
>

Attribute

Meaning

srcset

A comma-separated list of image URLs, each tagged with its real pixel width (e.g. 800w)

sizes

A comma-separated list of media conditions describing how wide the image will be RENDERED at each breakpoint

src

The fallback image for browsers that do not support srcset — always include it

Note
Read sizes left to right: the browser picks the first media condition that matches the viewport and uses its rendered width. The final entry (no condition) is the default for anything that did not match earlier conditions.
How the Browser Picks the "Best" Image
  1. The browser reads sizes to determine the CSS pixel width the image will render at, given the current viewport.

  2. It multiplies that width by the screen’s device pixel ratio (DPR) — e.g. 2x on a typical retina phone.

  3. It picks the smallest candidate from srcset whose width descriptor is greater than or equal to that target pixel value.

  4. The choice can differ between page loads or devices — this is intentional; the spec leaves the exact algorithm up to the browser to allow for network-aware and cache-aware heuristics.

Viewport: 375px wide phone, DPR 2 --> effective target ~750px
sizes says: image renders at 100vw at this width --> 375px CSS width
375 * 2 = 750px needed --> browser picks hero-800w.jpg (smallest candidate >= 750)

Viewport: 1440px wide desktop, DPR 1
sizes says: at max-width 1200px doesn't match, falls to default "800px"
800 * 1 = 800px needed --> browser picks hero-800w.jpg
Pixel-Density Descriptors (x)

When the image is always displayed at a fixed CSS size regardless of viewport (a logo, an avatar, an icon), you don't need sizes at all — use pixel-density descriptors instead. These tell the browser directly: "this file is meant for a 1x screen, this one for a 2x screen."

HTML
<img
  src="avatar.jpg"
  srcset="avatar.jpg 1x, avatar@2x.jpg 2x, avatar@3x.jpg 3x"
  alt="User avatar"
  width="64" height="64"
>

Descriptor type

Use when...

Requires sizes?

w (width)

The rendered size of the image changes across breakpoints

Yes

x (pixel density)

The rendered size is fixed; only the pixel density varies

No

Do not mix descriptor types
A single srcset must use either all w descriptors or all x descriptors — never both in the same attribute.
A Real Breakpoint Example

A blog post's hero image that spans the full content width on mobile, but is capped at 900px inside a centered container on larger screens:

HTML
<img
  src="article-hero-900w.jpg"
  srcset="
    article-hero-480w.jpg  480w,
    article-hero-900w.jpg  900w,
    article-hero-1400w.jpg 1400w,
    article-hero-2000w.jpg 2000w
  "
  sizes="(max-width: 900px) 100vw, 900px"
  alt="Team standing in front of the new office"
  width="900" height="500"
  loading="lazy"
>
Tip
Always include width and height attributes (or their aspect ratio via CSS) even when using srcset. The browser needs the intrinsic aspect ratio up front to reserve layout space and avoid content shifting as images load — this is a major factor in the Cumulative Layout Shift metric.
Common Mistakes
  • Forgetting sizes when using width (w) descriptors — without it, the browser assumes 100vw, which often picks a much larger image than necessary.

  • Listing srcset candidates out of order — order does not matter to the browser, but keeping them ascending makes the markup easier for humans to read and maintain.

  • Using only 2 candidate sizes for a widely responsive image — more steps (3–5) gives the browser finer-grained choices and saves more bandwidth on average.

  • Omitting the plain src fallback — required for the rare browser or crawler that ignores srcset entirely.

Key Takeaways
  1. srcset lists candidate image files; the browser — not you — picks the best one at load time.

  2. Width descriptors (w) work together with sizes to describe how large the image renders at each breakpoint.

  3. Pixel-density descriptors (x) are simpler and fit images with a fixed display size across all viewports.

  4. The picking algorithm considers rendered CSS size and device pixel ratio, and results can legitimately vary between browsers.

  5. Always keep width/height attributes to prevent layout shift, regardless of which descriptor type you use.