Implement responsive images with srcset
Images use srcset and sizes attributes for responsive delivery across devices.
- Use srcset to provide multiple image sizes
- Use sizes attribute to tell browser which size to download
- Browser selects optimal size based on viewport and DPR
- Can save 50-70% bandwidth on mobile devices
Rule Details
Responsive images deliver the right size image for each device, saving bandwidth and improving performance.
Code Example
<img
src="image-800.jpg"
srcset="
image-400.jpg 400w,
image-800.jpg 800w,
image-1200.jpg 1200w,
image-1600.jpg 1600w
"
sizes="(max-width: 600px) 100vw,
(max-width: 1200px) 50vw,
33vw"
alt="Responsive image"
width="800"
height="600"
>Why It Matters
Serving a 2000px image to a 400px phone screen wastes bandwidth and slows loading—srcset lets the browser download only the size it needs.
Understanding sizes Attribute
| sizes Value | Meaning |
|---|---|
100vw | Image takes full viewport width |
50vw | Image takes half viewport width |
(max-width: 600px) 100vw | Full width on screens up to 600px |
33vw | Default when no condition matches |
srcset with Pixel Density (x) Descriptors
<!-- For fixed-size images (icons, logos) -->
<img
src="logo.png"
srcset="
logo.png 1x,
logo@2x.png 2x,
logo@3x.png 3x
"
alt="Logo"
width="200"
height="50"
>Picture Element for Art Direction
<picture>
<!-- Different crop for mobile -->
<source
media="(max-width: 600px)"
srcset="hero-mobile.webp 600w, hero-mobile-2x.webp 1200w"
sizes="100vw"
type="image/webp"
>
<!-- Desktop version -->
<source
media="(min-width: 601px)"
srcset="hero-desktop.webp 1200w, hero-desktop-2x.webp 2400w"
sizes="100vw"
type="image/webp"
>
<!-- Fallback -->
<img src="hero-desktop.jpg" alt="Hero" width="1200" height="600">
</picture>React Responsive Image Component
interface ResponsiveImageProps {
src: string
alt: string
sizes: string
widths?: number[]
className?: string
}
function ResponsiveImage({
src,
alt,
sizes,
widths = [400, 800, 1200, 1600],
className
}: ResponsiveImageProps) {
const srcSet = widths
.map(w => `${getImageUrl(src, w)} ${w}w`)
.join(', ')
return (
<img
src={getImageUrl(src, widths[1])} // Default to medium size
srcSet={srcSet}
sizes={sizes}
alt={alt}
loading="lazy"
decoding="async"
className={className}
/>
)
}
function getImageUrl(src: string, width: number): string {
// Example: append width parameter for CDN
return `${src}?w=${width}`
}
// Usage
<ResponsiveImage
src="/images/hero.jpg"
alt="Hero image"
sizes="(max-width: 768px) 100vw, 50vw"
widths={[320, 640, 960, 1280]}
/>Next.js Automatic Responsive Images
import Image from 'next/image'
function ProductCard({ product }: { product: Product }) {
return (
<Image
src={product.image}
alt={product.name}
width={400}
height={300}
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 25vw"
// Next.js automatically generates srcset
/>
)
}Common sizes Patterns
<!-- Full width hero -->
<img sizes="100vw" ...>
<!-- Two-column layout on desktop -->
<img sizes="(min-width: 1024px) 50vw, 100vw" ...>
<!-- Three-column grid -->
<img sizes="(min-width: 1024px) 33vw, (min-width: 640px) 50vw, 100vw" ...>
<!-- Fixed sidebar, fluid main -->
<img sizes="(min-width: 1024px) calc(100vw - 300px), 100vw" ...>Generating Multiple Sizes
// Build script to generate image sizes
const sharp = require('sharp')
const sizes = [400, 800, 1200, 1600, 2000]
async function generateSizes(inputPath, outputDir) {
for (const width of sizes) {
await sharp(inputPath)
.resize(width)
.webp({ quality: 80 })
.toFile(`${outputDir}/image-${width}.webp`)
}
}Browser Selection Logic
The browser considers:
- Viewport width
- Device pixel ratio (DPR)
sizesattribute value- Available
srcsetoptions
Example: 400px viewport, 2x DPR, sizes="100vw"
- Needs: 400px × 2 = 800 CSS pixels worth of image data
- Browser selects: image-800.jpg (or next larger)Testing
- Open DevTools Network tab, filter by Images
- Resize viewport—different sizes should load
- Check which srcset variant was selected in Network details
- Test on real mobile devices (different DPRs)
- Use Lighthouse to verify responsive images are implemented
Verification
Automated Checks
- Re-test key pages in DevTools or WebPageTest after deployment to confirm the CDN or image component preserves the responsive variants.
Manual Checks
- Confirm the browser selects smaller image candidates on narrow viewports and higher-density variants on retina screens.
- Check that the
sizesattribute matches the real CSS layout; if the layout changes, updatesizesin the same PR. - Verify you are not sending a
1600wimage to a viewport that only renders it at a few hundred CSS pixels.
Use with AI
Copy these prompts to use with your AI assistant, or install the MCP server to use directly from Claude, Cursor, or Windsurf.
Check
Verify implementation
Verify that images use srcset and sizes attributes for responsive delivery.
Fix
Auto-fix issues
Implement responsive images with srcset for different screen sizes and resolutions.
Explain
Learn more
Explain how responsive images deliver optimized versions based on device capabilities.
Review
Code review
Inspect image markup and component abstractions for `srcset`, `sizes`, and width/height handling. Flag pages that always ship desktop-sized assets to mobile, omit `sizes`, or generate variants that do not match the actual rendered layout.