Responsive Images
A single large image works, but it wastes bandwidth on small screens that don’t need that many pixels. Responsive images let the browser pick the best image file for the device it’s running on.
srcset: offering multiple sizes
srcset lists multiple versions of the same image, each with its actual width using the w unit:
<img
src="photo-800.jpg"
srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1200.jpg 1200w"
alt="A mountain landscape at sunset"
/>
The browser picks whichever file makes sense for the device’s screen size and pixel density. src stays as a fallback for browsers that don’t support srcset.
sizes: telling the browser how big the image will display
srcset alone tells the browser what files exist. sizes tells it how much space the image will actually take up in the layout, so it can pick intelligently instead of guessing.
<img
src="photo-800.jpg"
srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1200.jpg 1200w"
sizes="(max-width: 600px) 100vw, 50vw"
alt="A mountain landscape at sunset"
/>
This reads as: “on screens up to 600px wide, the image takes the full viewport width (100vw); otherwise, it takes half the viewport width (50vw).” Match these values to your actual CSS layout, otherwise the browser is choosing based on wrong information.
The picture element: art direction
srcset and sizes serve the same image cropped at different resolutions. Sometimes you want a genuinely different crop on small screens, for example a tighter crop that keeps a subject visible on a narrow phone screen. That’s what <picture> is for.
<picture>
<source media="(max-width: 600px)" srcset="photo-square.jpg" />
<source media="(min-width: 601px)" srcset="photo-wide.jpg" />
<img src="photo-wide.jpg" alt="A mountain landscape at sunset" />
</picture>
The browser checks each <source> in order and uses the first one whose media condition matches. The <img> at the end is required, it’s both the fallback and the element that carries the alt text.
<picture> is also useful for serving modern image formats with a fallback:
<picture>
<source srcset="photo.avif" type="image/avif" />
<source srcset="photo.webp" type="image/webp" />
<img src="photo.jpg" alt="A mountain landscape at sunset" />
</picture>
Here the browser uses the first format it actually supports, falling back to the plain <img> if neither AVIF nor WebP is supported.
Which one do I need?
- Same image, different sizes: use
srcsetandsizeson a plain<img>. - Different crop or different image on different screens: use
<picture>withmediaconditions. - Modern format with a fallback: use
<picture>withtypeconditions.
Common mistakes
- Adding
srcsetwithoutsizes. Withoutsizes, the browser assumes the image fills the full viewport width, which often picks a larger file than necessary. - Forgetting
alton the<img>inside<picture>. It’s still required,<source>elements don’t carry alt text. - Listing image widths in
srcsetthat don’t match the files’ real dimensions.
What to read next
- Images
: the
imgelement basics and writing good alt text - CSS Responsive Design : media queries and fluid layouts