One file, many screens
An img element shows a picture. With only src, every screen downloads the same file, here cup-800.jpg. But screens differ: a small, plain screen wastes data on pixels it cannot show, and a big, sharp one stretches the picture until it looks soft.
Layout is measured in CSS pixels. The screen's dots of light are device pixels. devicePixelRatio says how many device pixels fit across one CSS pixel. Both screens here have 2, so a picture drawn 400 CSS pixels wide needs 800 pixels of image.
srcset and sizes
srcset lists the same picture saved at several widths. Each entry is a file and a width descriptor: 400w means this file is 400 pixels wide. The browser now has three candidates, and it will download only one of them.
sizes tells the browser how wide the image will be drawn: its slot, in CSS pixels. It is needed early, because the browser starts fetching images before the page's CSS is ready. The first true condition wins; the last value is the default.
The browser picks
A phone shows the page 400 CSS pixels wide. (max-width: 600px) means a viewport 600 pixels wide or less, so it is true. The browser stops at the first true condition: the slot is 100vw, the whole viewport, 400 CSS pixels.
The slot is 400 CSS pixels and the screen packs 2 device pixels into each, so it needs 400 × 2 = 800 pixels across. cup-800.jpg fits exactly, and only that file is downloaded. cup-1600.jpg would have been four times the pixels.
A laptop shows the page 1200 CSS pixels wide. Now (max-width: 600px) is false, so the browser moves on to the last value, 50vw: half the viewport. The slot is 600 CSS pixels.
600 CSS pixels × 2 = 1200 pixels needed. cup-800.jpg has too few and would look soft, so the browser takes the smallest file that is big enough: cup-1600.jpg. Same HTML, different download.
Good habits
width and height give the picture's shape before any file arrives: 800 by 600 is 4:3. The browser reserves a box of that shape in the slot, so the text below does not jump down when the image loads.
src is the fallback: a browser that does not understand srcset simply loads cup-800.jpg. alt is the text that stands in for the picture: screen readers read it aloud, and browsers show it if the image cannot load.
srcset swaps sizes of one picture. To swap the picture itself, such as a closer crop for narrow screens, wrap the img in <picture> with a <source media="(max-width: 600px)">. The first source that matches wins; the img is still required.
What happens
;; step 1/11 · one-file line 1 <img src="cup-800.jpg" src one file, for every screen small gets more pixels than it can show: wasted data large gets fewer than it can show: stretched, soft fix offer several sizes and let the browser choose
The HTML standard leaves the final choice to the browser. It may take a smaller file on a slow connection, or reuse a larger one it already has. Browsers aim for the smallest file with enough pixels, as in the figure. sizes is a promise about your CSS. Here the page's CSS would draw the image across the whole screen on narrow viewports and in a half-width column on wider ones, with height: auto keeping its 4:3 shape.