How to show different images on different screens
Short answer
Wrap <img> in <picture> and add a <source> with a media query before it. Change the window width to see the shot switch:
<picture>
<source media="(max-width: 500px)" srcset="/media/photo-200x200.jpg">
<img src="/media/photo-600x200.jpg" alt="A flower" style="max-width: 100%; height: auto;">
</picture>The browser goes through the <source> elements from top to bottom and takes the first match. If none matches, the file from <img> is shown. On a narrow screen a wide banner would turn into a strip, so a square shot works better there.
An image for the dark theme
Any media query fits into media, for example the system theme:
<picture>
<source media="(prefers-color-scheme: dark)" srcset="/media/photo-200x200.jpg">
<img src="/media/photo-400x250.jpg" alt="A flower" width="200">
</picture>Modern formats
The same technique serves WebP or AVIF to browsers that understand them, and JPEG to the rest. Instead of media, the type attribute is given:
<picture>
<source srcset="photo.avif" type="image/avif">
<source srcset="photo.webp" type="image/webp">
<img src="photo.jpg" alt="A flower" width="400" height="250">
</picture>Files in the new formats weigh noticeably less at the same quality.
Common mistake
Styles, sizes and alt are set on <picture> or <source>. They have no effect: <picture> only picks the file address, and the image is always shown by <img>. All the styling goes to it.
Functions used in this recipe
- <picture> — A container for several versions of an image: the browser picks a matching `<source>` or falls back to `<img>`.
- <source> — One of the file versions for `<video>`, `<audio>` or `<picture>`.
- <img> — An image.
- srcset — Several files of one image in different sizes: the browser picks the one that fits the screen.
- @media — Applies rules only under given conditions — the window width, the system theme and others.