Responsive Images: Best Practices for 2024
Optimize images for all devices and screen sizes.
Images make up the majority of bytes downloaded on most web pages. Serving the right image at the right size to the right device is critical for performance, user experience, and bandwidth costs. In this guide, you’ll learn modern techniques for responsive images including srcset, sizes, the picture element, and optimization strategies that work in 2024.
Responsive images aren’t just about scaling—they’re about delivering the perfect image for each user’s device, screen size, and network speed.
Why Responsive Images Matter
The Problem
A single 2MB image works fine on desktop with fast WiFi, but on mobile with slow 4G:
- Takes 10+ seconds to load
- Costs users money (limited data plans)
- Wastes bandwidth (mobile screens don’t need 4K images)
- Hurts performance metrics
- Frustrates users
The Solution
Serve appropriately sized images:
- Mobile: 400px wide image (50KB)
- Tablet: 800px wide image (150KB)
- Desktop: 1200px wide image (300KB)
- Retina displays: 2x versions when needed
The srcset Attribute
The simplest responsive image technique:
<img
src="image-small.jpg"
srcset="
image-small.jpg 400w,
image-medium.jpg 800w,
image-large.jpg 1200w,
image-xlarge.jpg 1600w"
sizes="100vw"
alt="Responsive image">How it works:
- Browser picks the best image based on screen width
400wmeans “this image is 400 pixels wide”sizestells browser how much space image will take- Browser considers device pixel ratio automatically
The sizes Attribute
Tell the browser how wide the image will be displayed:
<img
src="image.jpg"
srcset="
image-400.jpg 400w,
image-800.jpg 800w,
image-1200.jpg 1200w"
sizes="
(max-width: 600px) 100vw,
(max-width: 1200px) 50vw,
33vw"
alt="Image">Sizes explained:
- Mobile (≤600px): Image takes full width (100vw)
- Tablet (≤1200px): Image takes half width (50vw)
- Desktop: Image takes one-third width (33vw)
The Picture Element
Use <picture> for art direction—when you need different crops or formats:
<picture>
<!-- Modern format for supporting browsers -->
<source
type="image/webp"
srcset="
image-400.webp 400w,
image-800.webp 800w,
image-1200.webp 1200w"
sizes="100vw">
<!-- AVIF (even better compression) -->
<source
type="image/avif"
srcset="
image-400.avif 400w,
image-800.avif 800w,
image-1200.avif 1200w"
sizes="100vw">
<!-- Fallback to JPEG -->
<img
src="image-800.jpg"
srcset="
image-400.jpg 400w,
image-800.jpg 800w,
image-1200.jpg 1200w"
sizes="100vw"
alt="Responsive image with modern formats">
</picture>Art Direction
Show different images for different screen sizes:
<picture>
<!-- Mobile: Square crop focusing on subject -->
<source
media="(max-width: 600px)"
srcset="portrait-crop.jpg">
<!-- Tablet: Landscape crop -->
<source
media="(max-width: 1200px)"
srcset="landscape-crop.jpg">
<!-- Desktop: Full wide image -->
<img
src="full-width.jpg"
alt="Product photo">
</picture>Use art direction when:
- Mobile needs a cropped/zoomed version
- Orientation matters (portrait vs landscape)
- Image content should change with screen size
Image Formats in 2024
Format Comparison
AVIF (Best compression, newest)
- 50% smaller than JPEG
- Supported: Chrome, Firefox, Safari 16+
- Use with fallbacks
WebP (Great compression, widely supported)
- 30% smaller than JPEG
- Supported: All modern browsers
- Safe to use with JPEG fallback
JPEG (Universal compatibility)
- Supported everywhere
- Good for photos
- Always provide as fallback
PNG (Lossless, transparency)
- Larger file sizes
- Use for logos, graphics with transparency
- Consider WebP/AVIF versions
Using Modern Formats
<picture>
<!-- Best: AVIF -->
<source type="image/avif" srcset="image.avif">
<!-- Good: WebP -->
<source type="image/webp" srcset="image.webp">
<!-- Fallback: JPEG -->
<img src="image.jpg" alt="Image description">
</picture>Lazy Loading
Load images only when needed:
<!-- Native lazy loading -->
<img
src="image.jpg"
loading="lazy"
alt="Description">
<!-- Eager loading (default) -->
<img
src="hero.jpg"
loading="eager"
alt="Hero image">Best practices:
- Use
loading="lazy"for below-the-fold images - Use
loading="eager"for above-the-fold images - Don’t lazy-load hero images or critical content
Aspect Ratio Boxes
Prevent layout shift while images load:
<!-- Modern CSS aspect-ratio -->
<img
src="image.jpg"
alt="Description"
style="aspect-ratio: 16/9; width: 100%; object-fit: cover;">
<!-- Width and height attributes -->
<img
src="image.jpg"
width="1600"
height="900"
alt="Description"
style="width: 100%; height: auto;">Density Descriptors for Retina
Handle high-DPI displays:
<!-- Using pixel density descriptors -->
<img
src="image.jpg"
srcset="
image.jpg 1x,
image-2x.jpg 2x,
image-3x.jpg 3x"
alt="Logo">When to use:
- Fixed-size images (logos, icons)
- When width doesn’t change
- Simpler than width descriptors
Complete Responsive Image Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Responsive Images Demo</title>
<style>
img {
max-width: 100%;
height: auto;
display: block;
}
.hero-image {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1rem;
padding: 1rem;
}
</style>
</head>
<body>
<!-- Hero image with multiple formats -->
<picture>
<source
type="image/avif"
srcset="
hero-400.avif 400w,
hero-800.avif 800w,
hero-1200.avif 1200w,
hero-1600.avif 1600w"
sizes="100vw">
<source
type="image/webp"
srcset="
hero-400.webp 400w,
hero-800.webp 800w,
hero-1200.webp 1200w,
hero-1600.webp 1600w"
sizes="100vw">
<img
class="hero-image"
src="hero-800.jpg"
srcset="
hero-400.jpg 400w,
hero-800.jpg 800w,
hero-1200.jpg 1200w,
hero-1600.jpg 1600w"
sizes="100vw"
alt="Hero image"
loading="eager"
width="1600"
height="900">
</picture>
<!-- Grid of lazy-loaded images -->
<div class="grid">
<img
src="product-1-400.jpg"
srcset="
product-1-400.jpg 400w,
product-1-800.jpg 800w"
sizes="
(max-width: 600px) 100vw,
(max-width: 1200px) 50vw,
33vw"
alt="Product 1"
loading="lazy"
width="800"
height="600">
<img
src="product-2-400.jpg"
srcset="
product-2-400.jpg 400w,
product-2-800.jpg 800w"
sizes="
(max-width: 600px) 100vw,
(max-width: 1200px) 50vw,
33vw"
alt="Product 2"
loading="lazy"
width="800"
height="600">
</div>
</body>
</html>Image Optimization Tools
Build-Time Optimization
Command-line tools:
- ImageMagick - Convert and resize
- ffmpeg - Video thumbnails
- Sharp (Node.js) - Automated processing
- Squoosh CLI - Modern format conversion
# Convert to WebP
cwebp input.jpg -o output.webp -q 80
# Convert to AVIF
avifenc input.jpg output.avif -s 2
# Resize with ImageMagick
convert input.jpg -resize 800x output.jpgOnline Tools
- Squoosh.app - Google’s web-based optimizer
- TinyPNG - PNG and JPEG compression
- Cloudinary - CDN with automatic optimization
- ImageOptim - Mac app for compression
Automated Solutions
- Next.js Image component - Automatic optimization
- Cloudinary - On-the-fly transformations
- imgix - Real-time image processing
- Netlify Large Media - Git-based image optimization
Performance Best Practices
✅ Serve modern formats (AVIF, WebP) with fallbacks ✅ Use srcset and sizes for resolution switching ✅ Lazy load below-the-fold images ✅ Include width/height to prevent layout shift ✅ Compress images (aim for 80-85% quality) ✅ Use CDN for faster delivery ✅ Set proper cache headers ✅ Consider image CDNs for automatic optimization
Common Mistakes
❌ Single large image for all devices ❌ Not compressing images ❌ Lazy loading hero images ❌ Missing width/height causing layout shift ❌ Only using JPEG (miss WebP/AVIF savings) ❌ Not testing on slow connections ❌ Forgetting alt text ❌ Over-optimizing (too low quality)
Responsive Images Checklist
- ✅ Multiple image sizes generated (400, 800, 1200, 1600px)
- ✅ Modern formats provided (AVIF, WebP)
- ✅ srcset attribute with width descriptors
- ✅ sizes attribute with appropriate breakpoints
- ✅ Alt text for all images
- ✅ Width and height attributes set
- ✅ Lazy loading for below-fold images
- ✅ Compressed with appropriate quality
- ✅ Tested on various devices and connections
Testing Responsive Images
Browser DevTools
- Open DevTools Network tab
- Check which image size loads
- Test different viewport sizes
- Throttle network speed
- Verify format (WebP/AVIF vs JPEG)
Lighthouse Audit
Run Lighthouse to check:
- Properly sized images
- Modern image formats
- Offscreen images deferred
- Image compression
WebPageTest
Test with WebPageTest.org to see:
- Image download times
- Total image bytes
- Optimization opportunities
Future-Proof Strategies
Use Picture for Maximum Flexibility
<picture>
<!-- Future format -->
<source type="image/jxl" srcset="image.jxl">
<!-- Current best -->
<source type="image/avif" srcset="image.avif">
<!-- Widely supported -->
<source type="image/webp" srcset="image.webp">
<!-- Universal fallback -->
<img src="image.jpg" alt="Description">
</picture>Embrace Automation
Don’t manually create all image sizes. Use:
- Build tools (webpack, Vite, Next.js)
- Image CDNs (Cloudinary, imgix)
- CMS with automatic resizing
Keep Learning
- Mobile-First Development - Build for mobile
- Web Performance - Speed optimization
- HTML Best Practices - Avoid mistakes
- Explore Templates - See responsive images in action
Try responsive images in the htmlEditor.net playground today!
Responsive images are no longer optional—they’re essential for modern web development. Master srcset, sizes, and the picture element, and your users will enjoy faster, better experiences on every device.