Responsive Images
Responsive images load different sizes based on screen size and device capabilities. This improves performance and user experience.
Why Responsive Images?
- Performance — Don’t load 4K images on mobile
- Bandwidth — Save data on slow connections
- Quality — Serve appropriate resolution for each device
- Art Direction — Show different crops per screen size
Basic srcset
The srcset attribute offers multiple image versions:
<img
src="photo-800.jpg"
srcset="
photo-400.jpg 400w,
photo-800.jpg 800w,
photo-1200.jpg 1200w
"
alt="Responsive image"
/>
How it works:
- Browser chooses best image based on screen size
400w,800w,1200w= image width in pixels- Browser calculates which image fits best
Sizes Attribute
Tell the browser how wide the image will display:
<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="Responsive image"
/>
Sizes syntax:
(max-width: 600px) 100vw— On mobile, image is 100% of viewport800px— On desktop, image is 800px wide
Why sizes matters:
- Browser needs to know display size BEFORE loading image
- Without sizes, browser can’t choose optimal image
Complete srcset Example
<img
src="hero-800.jpg"
srcset="
hero-400.jpg 400w,
hero-800.jpg 800w,
hero-1200.jpg 1200w,
hero-1600.jpg 1600w
"
sizes="
(max-width: 480px) 100vw,
(max-width: 1024px) 50vw,
800px
"
alt="Hero image that adapts to screen size"
loading="lazy"
width="1600"
height="900"
/>
Breakdown:
- Mobile (< 480px): Loads 400w image
- Tablet (< 1024px): Loads 800w image
- Desktop: Loads 1200w or 1600w image
Retina Displays (HiDPI)
Serve higher resolution for retina screens:
<img
src="logo-200.jpg"
srcset="
logo-200.jpg 1x,
logo-400.jpg 2x,
logo-600.jpg 3x
"
alt="Logo"
/>
Resolution descriptors:
1x— Standard resolution2x— Retina (2x pixels)3x— Super retina (3x pixels)
Picture Element
For art direction (different crops per screen size):
<picture>
<!-- Desktop: wide crop -->
<source media="(min-width: 1024px)" srcset="hero-wide.jpg" />
<!-- Tablet: medium crop -->
<source media="(min-width: 600px)" srcset="hero-medium.jpg" />
<!-- Mobile: square crop -->
<img src="hero-square.jpg" alt="Hero image" />
</picture>
When to use picture:
- Different crops per device
- Different focal points
- Showing/hiding elements
- Art direction control
Picture with Format Selection
Serve modern formats to supporting browsers:
<picture>
<!-- Modern browsers: WebP -->
<source type="image/webp" srcset="photo.webp" />
<!-- Fallback: JPEG -->
<img src="photo.jpg" alt="Photo" />
</picture>
Format support:
- WebP: Chrome, Firefox, Edge, Safari 14+
- AVIF: Chrome, Firefox (better compression)
- JPEG: Universal fallback
Complete Picture Example
<picture>
<!-- Desktop: wide landscape -->
<source
media="(min-width: 1024px)"
type="image/webp"
srcset="hero-wide.webp"
/>
<source media="(min-width: 1024px)" srcset="hero-wide.jpg" />
<!-- Tablet: medium crop -->
<source
media="(min-width: 600px)"
type="image/webp"
srcset="hero-medium.webp"
/>
<source media="(min-width: 600px)" srcset="hero-medium.jpg" />
<!-- Mobile: square crop -->
<source type="image/webp" srcset="hero-square.webp" />
<img src="hero-square.jpg" alt="Hero image" width="800" height="800" />
</picture>
Loading Strategies
Lazy Loading
Load images only when visible:
<img src="photo.jpg" loading="lazy" alt="Lazy loaded" />
When to use:
- Images below the fold
- Image galleries
- Long pages with many images
Eager Loading
Load images immediately (default):
<img src="photo.jpg" loading="eager" alt="Eager loaded" />
When to use:
- Above-the-fold images
- Hero images
- Critical content
Complete Example
Here’s a responsive hero section:
<section class="hero">
<picture>
<!-- Desktop: wide crop -->
<source
media="(min-width: 1024px)"
type="image/webp"
srcset="hero-wide.webp"
/>
<source media="(min-width: 1024px)" srcset="hero-wide.jpg" />
<!-- Mobile: square crop -->
<source type="image/webp" srcset="hero-square.webp" />
<img
src="hero-square.jpg"
alt="Person learning web development"
loading="eager"
width="1200"
height="600"
/>
</picture>
<div class="hero-content">
<h1>Learn Web Development</h1>
<p>Start your journey today</p>
</div>
</section>
<section class="gallery">
<h2>Gallery</h2>
<div class="grid">
<!-- Lazy load gallery images -->
<img
src="gallery-400.jpg"
srcset="
gallery-400.jpg 400w,
gallery-800.jpg 800w
"
sizes="(max-width: 600px) 100vw, 400px"
alt="Gallery image 1"
loading="lazy"
/>
<img
src="gallery-400.jpg"
srcset="
gallery-400.jpg 400w,
gallery-800.jpg 800w
"
sizes="(max-width: 600px) 100vw, 400px"
alt="Gallery image 2"
loading="lazy"
/>
</div>
</section>
Best Practices
- Always provide srcset — Let browser choose optimal image
- Use sizes attribute — Helps browser calculate before loading
- Lazy load below fold — Improve initial page load
- Serve modern formats — WebP/AVIF with JPEG fallback
- Set width and height — Prevents layout shift (CLS)
Common Mistakes
- Missing sizes attribute — Browser can’t choose optimal image
- Not providing fallback src — Required for accessibility
- Lazy loading hero image — Above fold should load immediately
- Ignoring retina screens — Serve 2x for crisp images
- Same image for all devices — Wastes bandwidth on mobile