Back to HTML
HTML
easy
mid

How does the srcset attribute work and when would you use it for responsive images?

srcset is an <img>/<source> attribute that lists multiple image candidates so the browser picks the best one for the device. Two forms: width descriptors ('img-400.jpg 400w, img-800.jpg 800w') paired with sizes for responsive widths, or pixel-density descriptors ('img.jpg 1x, img@2x.jpg 2x') for fixed-width retina. Saves bandwidth on small/low-DPR screens and serves crisp images on retina without shipping huge files to everyone.

6 min read·~5 min to think through

srcset lets you give the browser a menu of image sources and trust it to pick the right one based on screen width, pixel density, and (via sizes) the rendered layout width.

Form 1: pixel-density descriptors (fixed-size images)

For images that always render at the same CSS pixel size (icons, avatars):

html
<img
  src="avatar.jpg"
  srcset="avatar.jpg 1x, avatar@2x.jpg 2x, avatar@3x.jpg 3x"
  alt="">

A 2x retina display downloads avatar@2x.jpg. A standard display gets avatar.jpg. Bandwidth saved on non-retina; crispness gained on retina.

Form 2: width descriptors + sizes (responsive images)

For images that change rendered width by viewport — like an article hero or product card:

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

The w after each URL is the image's intrinsic pixel width. sizes tells the browser how wide the image will render at the current viewport — a media-query-like list with the last value as default.

The browser does the math: viewport width × sizes value × device pixel ratio = "I need ~N CSS pixels worth of image." It picks the smallest srcset candidate that meets it.

When to use which

  • Pixel-density (x): fixed-size images (avatars, icons, logos).
  • Width (w) + sizes: anything that scales with viewport (hero images, article images, product photos, gallery thumbnails).

Pair with <picture> for art direction or format negotiation

srcset chooses between resolutions of the same image. <picture> chooses between different images (crop, format, art direction):

html
<picture>
  <source type="image/avif" srcset="hero.avif">
  <source type="image/webp" srcset="hero.webp">
  <img src="hero.jpg" alt="">
</picture>

Browser walks <source> top-to-bottom, takes the first format it supports. Modern formats (AVIF, WebP) cut bytes ~30–50% vs JPEG.

For art direction (different crop on mobile vs desktop):

html
<picture>
  <source media="(max-width: 600px)" srcset="hero-portrait.jpg">
  <img src="hero-landscape.jpg" srcset="hero-landscape@2x.jpg 2x" alt="">
</picture>

Gotchas

  • src is the fallback for browsers that don't understand srcset (essentially none today, but it's also what shows in copy-as-image, RSS, screenshots).
  • sizes is required when using w descriptors; without it the browser assumes 100vw.
  • The browser may pick a larger image than the smallest match (anticipating zoom, future viewport changes) — that's fine.
  • Don't list more than ~3–5 candidates; the savings flatten quickly.
  • Lazy-load below-the-fold: loading="lazy". Eager-load LCP image; preload it for max effect.

Tooling

Don't hand-author resized variants. Use:

  • next/image (Next.js) — generates srcset/sizes automatically.
  • Cloudinary / imgix / Cloudflare Images — on-the-fly resize via URL params.
  • sharp in a build step to generate the candidate set.

Follow-up questions

  • When would you use <picture> instead of just srcset?
  • How does srcset interact with loading='lazy' and fetchpriority?
  • What's the role of the sizes attribute and what happens without it?
  • How does AVIF/WebP negotiation work via <picture>?

Common mistakes

  • Using w descriptors without sizes — browser defaults to 100vw and picks larger images than needed.
  • Mixing x and w descriptors in one srcset — pick one.
  • Generating srcset variants smaller than the rendered size on hi-DPR screens — they look blurry.
  • Forgetting fallback src — old browsers (and copy-as-image) get nothing.
  • Listing 10+ candidates — diminishing returns and longer HTML.
  • Using srcset for art direction (different crop) — that's <picture media> territory.

Performance considerations

  • Responsive images are one of the highest-ROI perf wins. A typical hero image at 1600w is ~300KB; the mobile version at 400w is ~30KB. srcset shrinks LCP and total page weight dramatically. Pair with modern formats (AVIF ~50% smaller than JPEG) for compound wins. Always preload the LCP image: <link rel='preload' as='image' imagesrcset='…' imagesizes='…'>.

Edge cases

  • Save-Data header: serve smaller images when client signals data-saving mode.
  • Print stylesheets need higher-res sources; srcset doesn't account for print DPI directly.
  • fetchpriority='high' on the LCP image overrides lazy-loading heuristics for above-the-fold perf.
  • Foldable devices change effective viewport mid-session — browser may swap srcset candidates dynamically.

Real-world examples

  • Next.js <Image> generates srcset/sizes automatically and serves AVIF/WebP via Image Optimization.
  • Shopify, Cloudinary, and imgix URLs are designed for on-the-fly variant generation.
  • Wikipedia uses srcset extensively to serve resized thumbnails per device.

Senior engineer discussion

Seniors should understand the *math* (viewport × sizes × DPR) the browser does, the difference between x and w + sizes, and when to reach for <picture>. Bonus: knowing how to measure (Lighthouse 'Properly size images'), how preload + fetchpriority affect LCP, and how CDN/image services automate variant generation so engineers don't manually maintain candidate lists.

Related questions