Responsive Images Done Right: Mastering srcset, sizes, and the picture Element
Converting an image to WebP is only half the job. If you then serve that same 1600-pixel-wide file to a phone, a tablet, and a 4K monitor alike, you are still wasting megabytes on the devices that can never display them. Responsive images solve this by handing the browser a menu of files and letting it download exactly the right one. Master three tools — srcset, sizes, and <picture> — and you will never over-serve an image again.
Key Takeaways
- Use
srcsetwithwdescriptors to offer multiple widths of the same image. - The
sizesattribute tells the browser how wide the image will display, so it can choose correctly. - Use
xdescriptors for fixed-size images that only need to handle screen density. - Reach for
<picture>when you need art direction (different crops) or multiple file formats.
The Problem with One Fixed Image
A single <img src="photo.jpg"> forces every visitor to download the identical file. To look sharp on a high-resolution laptop, that file has to be large — but a phone on a cellular connection then pays the same penalty for pixels it cannot even render. The result is slow loads, blown data budgets, and a worse Largest Contentful Paint on exactly the mobile devices Google weights most heavily.
Resolution Switching with srcset and w Descriptors
The most common need is "same image, different sizes." You export the image at several widths, then list them in srcset with a w descriptor stating each file's intrinsic pixel width.
<img
src="photo-800.webp"
srcset="photo-400.webp 400w,
photo-800.webp 800w,
photo-1200.webp 1200w,
photo-1600.webp 1600w"
sizes="(max-width: 600px) 100vw, 50vw"
alt="Hot air balloons over a valley"
width="1200"
height="800"
loading="lazy"
>
The src still matters as a fallback for browsers that do not understand srcset. The w values describe each candidate; the browser combines them with the sizes hint and the device's pixel density to pick one file.
The sizes Attribute: The Part Everyone Forgets
Here is the crucial subtlety: when the browser begins choosing an image, it has often not yet calculated your CSS layout. It does not know that your image will render at half the viewport width. The sizes attribute is how you tell it in advance.
Read sizes="(max-width: 600px) 100vw, 50vw" as: "If the viewport is 600px or narrower, this image fills 100% of the viewport width; otherwise it occupies 50%." The browser multiplies that display width by the device pixel ratio to find the ideal source. Omit sizes and the browser assumes 100vw, frequently downloading a file far larger than needed.
Keep sizes honest
Your sizes value must reflect your actual CSS. If a redesign changes a column from 50% to 33% of the page, update sizes too — otherwise the browser keeps fetching oversized images and your savings quietly evaporate.
Density Switching with x Descriptors
Sometimes an image renders at a single fixed size — an avatar, an icon, a logo — and the only variable is screen density. For these, the simpler x descriptor is perfect. No sizes attribute is required.
<!-- A 100x100 avatar that stays crisp on retina screens -->
<img
src="avatar-100.webp"
srcset="avatar-100.webp 1x,
avatar-200.webp 2x,
avatar-300.webp 3x"
alt="User profile photo"
width="100"
height="100"
>
Art Direction with the picture Element
Resolution switching always serves the same image, just scaled. But what if a wide desktop hero looks terrible when squeezed onto a phone, and you would rather show a tighter, portrait crop? That is art direction, and it is the job of <picture> with media conditions.
<picture>
<!-- Narrow screens get a tighter, taller crop -->
<source media="(max-width: 600px)" srcset="hero-portrait.webp">
<!-- Wider screens get the full landscape shot -->
<source media="(min-width: 601px)" srcset="hero-landscape.webp">
<img src="hero-landscape.webp" alt="Team collaborating in an office"
width="1200" height="600">
</picture>
Combining Formats and Responsiveness
The two techniques compose beautifully. You can nest srcset and sizes inside the sources of a <picture> to deliver both the right format and the right resolution at once — AVIF or WebP for capable browsers, scaled to the exact device width, with a JPEG safety net.
<picture>
<source
type="image/webp"
srcset="photo-800.webp 800w, photo-1600.webp 1600w"
sizes="(max-width: 600px) 100vw, 50vw">
<img
src="photo-800.jpg"
srcset="photo-800.jpg 800w, photo-1600.jpg 1600w"
sizes="(max-width: 600px) 100vw, 50vw"
alt="Coastline at golden hour"
width="1600" height="900" loading="lazy">
</picture>
Common Mistakes to Avoid
- Forgetting
sizeswithwdescriptors — the browser defaults to100vwand over-downloads. - Omitting
widthandheight— you reintroduce layout shift even with perfect responsive sources. - Lazy-loading the LCP image — your above-the-fold hero should load eagerly, responsive or not.
- Too many breakpoints — three or four well-chosen widths cover almost every device; a dozen just bloats your build.
Responsive images reward a little upfront effort with dramatic, device-specific savings. Pair them with a modern format and explicit dimensions, and you have the complete recipe for images that are fast everywhere and stable on every screen.
Generate your responsive widths
Every entry in a srcset should be an optimized WebP. Resize and convert each width in seconds with our free, browser-based optimizer — your files never leave your device.
About WebPMagic
WebPMagic is an independent project focused on image optimization and web performance. These guides are researched and edited to give developers clear, practical, and accurate information for building faster websites, with tips drawn from hands-on use of our own WebP conversion tool. Found an error or have a suggestion? Let us know via our contact page.