Responsive Images
Prerequisites: Images
A phone doesn't need a 2400-pixel-wide photo, and a large high-density screen looks blurry with a small one. Responsive images let the browser choose.
Different sizes: srcset with w and sizes
<img
src="img/market-1200.jpg"
srcset="img/market-480.jpg 480w,
img/market-800.jpg 800w,
img/market-1200.jpg 1200w,
img/market-2000.jpg 2000w"
sizes="(min-width: 1000px) 50vw, 100vw"
alt="Fruit stalls at the Saturday market"
width="1200" height="800">
srcsetlists the files and their real widths (480w= 480 pixels wide).sizestells the browser how wide the image will be displayed: half the viewport on screens at least 1000 pixels wide, otherwise the full viewport. The first matching condition wins. The browser needs this before CSS has loaded.- The browser multiplies the display width by the screen's pixel density
and picks a suitable file. On a 400-pixel-wide phone with 2× density,
the image is 400 CSS pixels = 800 device pixels wide, so it will likely
pick
market-800.jpg. srcis the fallback for very old browsers.
The browser is free to choose differently — for example a smaller file
on a slow connection — so treat srcset as a list of options, not
commands.
Fixed-size images: x descriptors
For an image always shown at the same size (a logo, an avatar):
<img src="avatar-64.png" srcset="avatar-64.png 1x, avatar-128.png 2x" alt="Sam Lee" width="64" height="64">
Different images: picture
picture lets you change the image itself — art direction — or offer
newer formats:
<picture>
<source media="(max-width: 600px)" srcset="img/team-portrait.jpg" width="600" height="800">
<source type="image/avif" srcset="img/team-wide.avif">
<source type="image/webp" srcset="img/team-wide.webp">
<img src="img/team-wide.jpg" alt="Our team of six bakers in front of the shop" width="1600" height="900">
</picture>
- The browser uses the first
sourcethat matches (media) and that it supports (type), otherwise theimg. - The
imgis required: it's what actually displays, and it carries thealt,width/height,loading, and CSS classes. - A
sourcecan have its ownwidth/heightwhen its aspect ratio differs.
Lazy loading and priority
<img src="img/hero.jpg" alt="Loaves cooling on racks" width="1600" height="900" fetchpriority="high">
<img src="img/footer-map.png" alt="Map showing the shop two blocks from the station" width="800" height="400" loading="lazy">
loading="lazy"delays images until they're about to scroll into view. Use it for images below the fold — never on the main image at the top, or it loads later.fetchpriority="high"hints that an image is important (usually the largest image in the first screen). Supported in Chrome and Edge 101, Safari 17.2, and Firefox 132.decoding="async"lets the browser decode the image off the main thread.
The validator checks sizes
<!-- Wrong: w descriptors without sizes -->
<img src="a-800.jpg" srcset="a-400.jpg 400w, a-800.jpg 800w" alt="Example" width="800" height="600">
error: When the 'srcset' attribute has any image candidate string with a width descriptor, the 'sizes' attribute must also be specified.
Browsers are adding sizes="auto" for lazy-loaded images (the
browser measures the layout itself; Chrome and Edge since version 126).
Because older browsers ignore it, list real sizes after it as a fallback:
sizes="auto, (min-width: 1000px) 50vw, 100vw".
Practice
A blog shows article images full width on phones and at 720 pixels on
screens 800 pixels and wider. Write the img using files
post-400.jpg, post-720.jpg, and post-1440.jpg (original size
1440×960).
Show solution
<img src="post-720.jpg"
srcset="post-400.jpg 400w, post-720.jpg 720w, post-1440.jpg 1440w"
sizes="(min-width: 800px) 720px, 100vw"
alt="Describe the image here" width="1440" height="960" loading="lazy">
Leave off loading="lazy" if the image is at the top of the page.