skip to content

On an HTML <img>, what do the srcset and sizes attributes do, and what is the difference between a w descriptor and an x descriptor inside srcset?

level: juniorimportance: must knowfreq 72%

answer

  1. one image, several encodings
  2. descriptor describes the file
  3. display width must be declared too
  4. fixed box wants density, not width

basics

~20 s

srcset lists interchangeable files for one image: a w descriptor states a file's intrinsic pixel width, an x descriptor targets a device pixel ratio. sizes declares how wide the image will render, which the browser needs to choose among w candidates.

solid answer

~50 s

`srcset` on `<img>` gives the browser a menu of the *same* picture at different resolutions, and the browser picks one. Each candidate carries a descriptor. A **w descriptor** (`hero-800.jpg 800w`) states the file's real pixel width, and it only becomes useful when you also give `sizes` — a CSS length telling the browser how wide the image will actually be laid out, optionally with media conditions like `sizes="(min-width: 900px) 45vw, 100vw"`. From those two the browser works out how many pixels it needs and picks a candidate. An **x descriptor** (`[email protected] 2x`) targets device pixel ratio directly and is right when the rendered size is fixed — a logo or an avatar — because then `sizes` is irrelevant and is ignored. `src` stays as the fallback for anything that does not understand `srcset`. Same image content in every candidate: switching art or crop is `<picture>`'s job, not `srcset`'s.

code

html · 5 lines
html
<img src="photo-800.jpg"
     srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1600.jpg 1600w"
     sizes="(min-width: 900px) 45vw, 100vw"
     width="1600" height="900"
     alt="Harbour at dawn">

go deeper

for a junior

Be ready to write a correct <img> with srcset and sizes from memory and to say plainly that a w descriptor is the file's own pixel width, not a breakpoint.

for a middle

Explain when x descriptors are the better tool, what the default sizes value is, and why every candidate has to be the same picture rather than a different crop.

for a senior

Show you can pick a candidate ladder that is worth building and serving, and explain what role src still plays once srcset is present.

for a principal

Own the tradeoff between generating many derivatives per image and the build, storage and cache cost of doing so, and where that decision lives in a design system.

## The problem responsive images solve A single `src` forces one file on every visitor. A 2000-pixel-wide photograph is right for a wide desktop on a high-density screen and badly wrong for a phone that will paint it 360 CSS pixels across: the phone downloads and decodes several times the bytes it can display. Serving the small file to everyone fixes the phone and leaves the desktop blurry. `srcset` exists so the author can publish several encodings of the *same* image and let the browser choose. ## The srcset syntax `srcset` is a comma-separated list of *image candidate strings*. Each is a URL plus an optional descriptor: ```html <img src="photo-800.jpg" srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1600.jpg 1600w" sizes="(min-width: 900px) 45vw, 100vw" alt="…"> ``` Every candidate must be the same picture — same subject, same crop, same aspect ratio — just encoded at different sizes. Choosing a *different* crop per breakpoint is art direction and belongs to `<picture>` with `<source media>`, not here. ## w descriptors: the file's intrinsic width `photo-800.jpg 800w` says: this file is 800 image pixels wide. It is a statement about the file, not about the viewport and not about a breakpoint. This is the single most common misreading — people write `800w` believing it means "use this below 800px of viewport". It does not; the browser derives that decision itself. To derive it, the browser needs one more fact: how wide the image will be *displayed*. That is what `sizes` supplies. ## sizes: the display width, in CSS pixels `sizes` is a comma-separated list of `<media-condition> <length>` pairs, with a final bare length as the fallback. The browser evaluates the conditions in order and uses the length from the **first** match: ```html sizes="(min-width: 1200px) 600px, (min-width: 640px) 50vw, 100vw" ``` Lengths may be `px`, `em`, `rem`, `vw`, or `calc()` — but **not percentages**, because a percentage would need a containing block the browser has not laid out yet. If `sizes` is omitted while w descriptors are present, the browser assumes `100vw`, which is why full-bleed images accidentally look fine and constrained ones silently over-download. ## x descriptors: density switching When an image's rendered size is fixed by design — an avatar always 48 CSS pixels, a logo always 120 — you do not need the whole `sizes` machinery. You need one file per screen density: ```html <img src="avatar.png" srcset="avatar.png 1x, [email protected] 2x, [email protected] 3x" width="48" height="48" alt=""> ``` With x descriptors, `sizes` has no effect and is ignored. A candidate with no descriptor at all is treated as `1x`. Do not mix the two descriptor kinds in one `srcset`; the HTML standard treats a list that combines width and pixel-density descriptors as an error, so the safe rule is one descriptor type per attribute. ## What src is for once srcset exists `src` remains the fallback for anything that does not implement `srcset`. Beyond that its role depends on the descriptors: when every candidate is an x descriptor and none is `1x`, `src` participates as the `1x` candidate; when any candidate carries a w descriptor, `src` takes no part in the selection and is purely the fallback. Keep pointing it at a sensible mid-size file rather than the largest one. ## Which one should you reach for Ask whether the image's layout width varies with the viewport. - **It varies** (hero, article figure, card in a fluid grid) → w descriptors plus an honest `sizes`. - **It is fixed** (icon, logo, fixed-size avatar) → x descriptors, plus `width`/`height` attributes so the box is known. ## The mistakes that ship - Reading `800w` as a breakpoint and building a fake media-query ladder out of it. - Omitting `sizes` on a constrained image and inheriting the `100vw` default. - Putting a different crop in each candidate — the browser may swap between them at any moment, so the composition changes unpredictably. - Offering candidates that barely differ (`900w`, `950w`, `1000w`): more files to build and cache for no visible gain. - Forgetting `alt`; the responsive plumbing does nothing for accessibility.

  • If srcset lets the browser choose, why would you ever still use x descriptors?
    Because when the rendered box is fixed by design — a 48px avatar, a 120px logo — there is nothing for the browser to compute. `sizes` would just restate a constant, and x descriptors say the only thing that varies: screen density. They are shorter, they cannot go stale when the CSS changes, and they express the intent directly.
  • Can you put different crops of the picture in the same srcset to get a tighter mobile composition?
    No. Every candidate in one `srcset` must be the same image content; the browser may switch between them at will, including after load, so a differing crop would change the composition unpredictably. Art direction — a different crop or a different subject per breakpoint — is what `<picture>` with `<source media>` is for.
  • What happens to a browser that does not support srcset at all?
    It ignores `srcset` and `sizes` as unknown attributes and loads `src`, which is why `src` should point at a sensible middle-sized file rather than the largest candidate. Support is effectively universal in current browsers, so `src` is a safety net rather than a real strategy.

srcset is a menu of the same dish in different portion sizes; sizes is you telling the waiter how big the plate is. Without the plate size, the kitchen guesses the largest one.

saying these in an interview costs you the question

  • Thinks 800w means "use below an 800px viewport"
  • Puts different crops or subjects in one srcset
  • Mixes w and x descriptors in the same srcset
  • Omits sizes and assumes the browser measures the element
  • Points src at the largest file as the fallback

context