Serve Responsive Images: Right Size for Every Screen
Serving a 2000px image to a 400px phone screen wastes bandwidth. Learn how to use srcset, sizes, and responsive image techniques.
A 2000×1500px hero image looks great on a 4K monitor but is absurd on a 375px phone screen. Responsive images ensure every user downloads only the pixels they need.
Why Properly-Sized Images Matter
- Mobile users download desktop images — wasting data and battery
- Direct LCP impact — oversized hero images delay the largest contentful paint
- Easy to automate — build tools can generate all sizes for you
| Device | Screen Width | Ideal Image Width | Savings vs 2000px |
|---|---|---|---|
| Phone | 375px | 400px | ~80% |
| Tablet | 768px | 800px | ~60% |
| Laptop | 1440px | 1440px | ~28% |
| Desktop | 1920px | 2000px | 0% |
How to Implement Responsive Images
1. Using srcset and sizes
<img
src="/images/hero-800.webp"
srcset="
/images/hero-400.webp 400w,
/images/hero-800.webp 800w,
/images/hero-1200.webp 1200w,
/images/hero-2000.webp 2000w
"
sizes="
(max-width: 640px) 100vw,
(max-width: 1024px) 80vw,
1200px
"
alt="Hero image"
width="2000"
height="1000"
loading="eager"
/>
How it works:
srcsetlists available images and their widthssizestells the browser how wide the image will be at each breakpoint- The browser combines
sizes+ device pixel ratio to pick the best image
2. The <picture> Element for Art Direction
When you need different crops at different sizes:
<picture>
<!-- Mobile: square crop -->
<source
media="(max-width: 640px)"
srcset="/images/hero-mobile.webp 640w"
sizes="100vw"
/>
<!-- Desktop: wide crop -->
<source
srcset="/images/hero-desktop.webp 1200w, /images/hero-desktop-2x.webp 2400w"
sizes="(max-width: 1200px) 100vw, 1200px"
/>
<img src="/images/hero-desktop.webp" alt="Hero" width="1200" height="600" />
</picture>
3. Next.js Image Component
Next.js generates responsive images automatically:
import Image from "next/image";
// Fill mode — responsive to container
<div className="relative w-full aspect-video">
<Image
src="/images/hero.jpg"
alt="Hero"
fill
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 80vw, 1200px"
priority
/>
</div>
// Fixed dimensions with responsive srcset
<Image
src="/images/product.jpg"
alt="Product"
width={800}
height={600}
sizes="(max-width: 640px) 100vw, 50vw"
/>
4. Generating Multiple Sizes at Build Time
Use Sharp to create image variants:
import sharp from "sharp";
const sizes = [400, 800, 1200, 2000];
for (const width of sizes) {
await sharp("hero-original.jpg")
.resize(width)
.webp({ quality: 80 })
.toFile(`hero-${width}.webp`);
}
Or use a bulk script:
#!/bin/bash
for img in images/originals/*.jpg; do
name=$(basename "$img" .jpg)
for size in 400 800 1200 2000; do
npx sharp-cli resize $size -i "$img" \
-o "images/responsive/${name}-${size}.webp" \
--format webp --quality 80
done
done
5. Image CDN (Zero Build Config)
Image CDNs generate sizes on the fly:
<!-- Cloudinary: width parameter -->
<img
srcset="
https://res.cloudinary.com/demo/image/upload/w_400/hero.jpg 400w,
https://res.cloudinary.com/demo/image/upload/w_800/hero.jpg 800w,
https://res.cloudinary.com/demo/image/upload/w_1200/hero.jpg 1200w
"
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 80vw, 1200px"
alt="Hero"
/>
Common Mistakes
Not Setting the sizes Attribute
Without sizes, the browser assumes the image is 100vw wide and may download an unnecessarily large version.
Using CSS to Resize
/* ❌ Downloads a 2000px image, then shrinks it visually */
img { max-width: 100%; height: auto; }
CSS resizing doesn't save bandwidth — the full image is still downloaded.
Ignoring Device Pixel Ratio
A 375px phone with 3× DPR needs a 1125px image for sharp rendering. Your srcset should include sizes that account for common DPRs (1×, 2×, 3×).
Quick Wins Checklist
- Generate 3-5 image sizes for each major image
- Add
srcsetandsizesto all content images - Use Next.js Image or an image CDN for automatic sizing
- Set the
sizesattribute accurately based on your layout - Include sizes for 2× and 3× device pixel ratios
- Test on mobile DevTools with network throttling
Ready to stop wasting ad spend?
Track your landing page performance, monitor Core Web Vitals, and calculate exactly how much slow pages cost you.
Start Free — No Credit Card