Problem Solved

HTML · srcset & sizes

Home › Courses › HTML › Problems › srcset & sizes
📄 Concept · 4 min read

Responsive images with srcset.
The right image for every screen.

A hero image at 1200px downloaded on a 400px phone is wasted bandwidth — often 1–3 MB per image. srcset and sizes tell the browser to pick the right file: a 400w image for the phone, an 800w for the tablet, a 1200w for the desktop. No JavaScript, no server logic, no library. This page covers the markup, the sizes hint, and the <picture> element for art direction.

Short answer: Add srcset="image-400.jpg 400w, image-800.jpg 800w, image-1200.jpg 1200w" and sizes="(min-width: 768px) 50vw, 100vw" to your <img>. The browser calculates which file to download based on the viewport and DPR. Keep src="image-800.jpg" as the fallback. For different crops (not just sizes), use <picture> with multiple <source> tags.

✅ srcset — same image, different sizes

Width descriptors tell the browser the actual pixel width of each file.

srcset-widths.html
<img
src="hero-800.jpg"
srcset="hero-400.jpg 400w,
hero-800.jpg 800w,
hero-1200.jpg 1200w,
hero-1600.jpg 1600w"
sizes="(min-width: 1024px) 50vw,
(min-width: 768px) 70vw,
100vw"
alt="Product on a desk">
Phone (400px, 1x): downloads hero-400.jpg
Phone (400px, 2x): downloads hero-800.jpg
Tablet (768px, 1x): downloads hero-800.jpg
Desktop (1440px, 1x): downloads hero-1200.jpg
Desktop (1440px, 2x): downloads hero-1600.jpg

The browser picks the smallest file that fits the
render width × DPR. You only write the markup once.

Width descriptors (w)

400w means the file is 400 pixels wide. The browser compares this to the render size to pick the best.

The sizes hint

Without sizes, the browser assumes 100vw (full width). Tell it the actual render width at each breakpoint.

The src fallback

Always include src. Old browsers, and browsers that fail to parse srcset, use it.

Same image, different sizes

srcset is for size — the same photo at 400, 800, 1200. Not for different crops or aspect ratios.

✅ DPR descriptors — fixed-size images

For logos and icons that render at the same size on every screen.

srcset-dpr.html
<!-- Logo at 1x, 2x, 3x — same CSS size everywhere -->
<img
src="logo-1x.png"
srcset="logo-1x.png 1x,
logo-2x.png 2x,
logo-3x.png 3x"
width="120" height="40"
alt="Acme Corp">
Standard display (1x) → logo-1x.png
Retina / HiDPI (2x) → logo-2x.png
High-end phone (3x) → logo-3x.png

Use DPR descriptors when:
✅ Image has fixed CSS size (width="120")
✅ Image is a logo, icon, or avatar
✅ Layout doesn't change on mobile

Use width descriptors (w) when:
✅ Image is fluid (fills its container)
✅ Layout is responsive
✅ Image is a hero or featured visual

✅ picture — different crops, different formats

When the image itself changes, not just its size.

picture.html
<picture>
<!-- WebP for browsers that support it -->
<source type="image/webp"
srcset="hero.webp 800w, hero-1200.webp 1200w">

<!-- Different crop on mobile (portrait) -->
<source media="(max-width: 767px)"
srcset="hero-square.jpg 600w">

<!-- Fallback for everything else -->
<img src="hero.jpg"
srcset="hero.jpg 800w, hero-1200.jpg 1200w"
sizes="100vw"
alt="Wide banner: Acme launches Q4">
</picture>
Modern browser on desktop → hero.webp (800w or 1200w)
Old browser on desktop → hero.jpg (800w or 1200w)
Any browser on phone → hero-square.jpg (600w)

picture checks sources in order:
1. type="image/webp" → if browser supports WebP
2. media="(max-width: 767px)" → if viewport is narrow
3. img → fallback if nothing else matches

⚠️ The img inside picture is required.
It's the fallback and holds the alt attribute.

Don't use <picture> when srcset alone will do. <picture> is for art direction (different crops) and format fallback (WebP, AVIF). If you just need the same image at different sizes, use <img srcset>. It's simpler, has fewer moving parts, and the browser can optimize better. Reach for <picture> only when the image content itself changes.

⚠️ Common mistakes

The srcset mistakes that cost real time.

1. Omitting sizes

Browser assumes 100vw and downloads a too-large file. Fix: add the sizes hint.

2. Wrong sizes value

sizes="100vw" on an image that renders at 50% — downloads 2× larger than needed. Fix: match the actual render width.

3. Mixing w and x

srcset="a.jpg 400w, b.jpg 2x" is invalid. Fix: pick one descriptor type per element.

4. Forgetting src

Some browsers render nothing without a fallback. Fix: always include src.

5. Using srcset for art direction

Different crops don't fit the srcset model. Fix: use <picture> with <source>.

6. No width and height

Layout shifts as images load. Fix: set width and height — the browser reserves space.

7. Forgetting alt on the inner <img>

The fallback in <picture> still needs alt. Fix: put alt on the inner <img>.

8. Generating all sizes from a tiny source

Upscaling degrades quality. Fix: generate srcset files from a high-resolution original.

❓ Frequently asked

What is srcset in HTML?

srcset is an attribute on img that lists multiple image files with their widths or pixel densities. The browser picks the best one for the current screen. You provide the same image at different sizes: image-400.jpg 400w, image-800.jpg 800w, image-1200.jpg 1200w. The browser reads the screen width, the device pixel ratio, and the sizes hint, then downloads only one file. No JavaScript, no server logic. It is the standard way to serve responsive images.

What does the sizes attribute do?

sizes tells the browser how wide the image will render at different viewport widths. Without it, the browser assumes the image is 100vw (full viewport width), which is often wrong. For an image that takes 50% of the viewport, write sizes='50vw'. For a card grid that shows 3 columns on desktop and 1 on mobile, write sizes='(min-width: 768px) 33vw, 100vw'. The browser uses sizes to calculate which srcset candidate to download. Get sizes wrong and the browser downloads too large or too small an image.

What is the difference between srcset and picture?

srcset picks between different sizes of the same image — same content, different resolutions. picture picks between different images entirely — different crops, different aspect ratios, different formats (like WebP vs JPEG). Use srcset for the same photo at 400px, 800px, 1200px. Use picture when you need art direction (a wide banner on desktop, a tall crop on mobile) or format fallback (AVIF for modern browsers, JPEG for old ones).

What is a device pixel ratio (DPR) descriptor?

Instead of width descriptors (400w, 800w), you can use pixel density descriptors (1x, 2x, 3x). These describe the image's pixel density relative to CSS pixels. 1x is a standard display, 2x is a Retina/HiDPI screen, 3x is a high-end phone. Use DPR descriptors when the image renders at a fixed size on every device — like a logo in a fixed-width header. Use width descriptors for fluid images that change size with the viewport. The two cannot be mixed in the same srcset.

Does srcset improve page speed?

Yes, dramatically. Without srcset, mobile users download the same large image as desktop users — often 1-3 MB per hero image. With srcset, a phone downloads the 400w version (80-150 KB) instead of the 1200w version. That's a 10x reduction in image bytes. Combine with loading='lazy' for below-fold images and WebP/AVIF formats for further savings. On real-world sites, srcset plus format selection cuts image payload by 50-80% on mobile.

What happens if srcset isn't supported?

The browser falls back to the src attribute. Every img with srcset must still have a src attribute pointing to a default image — usually the middle-size or largest version. Modern browsers (all browsers since 2015) support srcset. The src fallback is for very old browsers and for edge cases where the browser can't parse the srcset. If you omit src, some browsers render nothing. Always include src as the fallback.

🔗 Related

← All HTML problems
Problem solved · HTML