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.
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):
<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:
<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):
<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):
<picture>
<source media="(max-width: 600px)" srcset="hero-portrait.jpg">
<img src="hero-landscape.jpg" srcset="hero-landscape@2x.jpg 2x" alt="">
</picture>Gotchas
srcis the fallback for browsers that don't understand srcset (essentially none today, but it's also what shows in copy-as-image, RSS, screenshots).sizesis required when usingwdescriptors; 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.
sharpin 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.