Why "One Image for Everyone" Wastes Bandwidth
A 2000px-wide hero image looks great on a desktop monitor, but serving that same file to a 360px-wide phone screen wastes 80%+ of the download. Multiply that across millions of mobile visits and you're looking at real money in bandwidth and real seconds in load time.
The fix isn't picking one "good enough" size. It's giving the browser several options and a set of rules, then letting it choose.
The srcset Attribute: Listing Your Options
The srcset attribute tells the browser which image files are available and how wide each one is:
<img
src="photo-800.jpg"
srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1200.jpg 1200w, photo-2000.jpg 2000w"
alt="Product photo"
/>
Each entry pairs a file with its intrinsic pixel width (the "w" descriptor, not a CSS size). The browser then picks the smallest file that still satisfies the space the image will occupy on screen, accounting for device pixel ratio (Retina/HiDPI screens need more actual pixels per CSS pixel).
The sizes Attribute: Telling the Browser How Big the Slot Is
srcset alone isn't enough. The browser also needs to know how much screen space the image will fill, which depends on your CSS layout. That's what sizes is for:
<img
src="photo-800.jpg"
srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1200.jpg 1200w, photo-2000.jpg 2000w"
sizes="(max-width: 600px) 100vw, (max-width: 1200px) 50vw, 800px"
alt="Product photo"
/>
Read it as a list of conditions evaluated in order: "On screens up to 600px wide, the image takes the full viewport width (100vw). On screens up to 1200px, it takes half the viewport (50vw). Otherwise, it's a fixed 800px." The browser combines this with srcset and the device's pixel density to pick the optimal file before it even starts downloading.
A Common Mistake: Skipping sizes
Without sizes, browsers default to 100vw, meaning they assume your image fills the entire viewport. If your image actually displays at, say, 33% width in a three-column grid, the browser will still download a much larger file than necessary because it doesn't know better. Always pair srcset with an accurate sizes value when the image isn't full-width.
How Many Sizes Should You Generate?
You don't need a file for every possible width. A practical, well-tested set:
| Use case | Recommended widths |
|---|---|
| Full-width hero images | 640w, 1024w, 1600w, 2048w |
| Content/blog images | 400w, 800w, 1200w |
| Thumbnails / grid items | 200w, 400w, 600w |
| Avatars / icons | 64w, 128w, 256w |
A roughly 1.5-2x jump between each size keeps the total number of files manageable while covering most real-world viewport widths efficiently.
The picture Element: For Format Switching, Not Just Sizing
If you also want to serve modern formats like WebP or AVIF with JPG fallbacks, wrap everything in a picture element:
<picture>
<source type="image/webp" srcset="photo-400.webp 400w, photo-800.webp 800w, photo-1200.webp 1200w" sizes="(max-width: 600px) 100vw, 800px">
<img src="photo-800.jpg" srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1200.jpg 1200w" sizes="(max-width: 600px) 100vw, 800px" alt="Product photo">
</picture>
The browser picks the first source it supports, falling back to the plain img for older browsers.
A Simple Workflow to Generate Your Files
Quick Checklist Before You Ship
Get this right once, on a reusable component or template, and every image on your site benefits: faster loads, lower bandwidth bills, and better Core Web Vitals scores.
Use our Image Resizer, Image Compressor, and WebP Converter to generate every size you need, right in your browser.