Media Element
HTML5
The picture element provides a container for multiple image sources, enabling art direction (different images for different layouts) and format fallbacks. It gives developers precise control over which image is displayed based on viewport size, device capabilities, and format support.
Interactive code playground requires JavaScript. Here's the code:
<picture>
<source media="(min-width: 800px)"
srcset="https://picsum.photos/1200/400">
<source media="(min-width: 400px)"
srcset="https://picsum.photos/800/400">
<img src="https://picsum.photos/400/300"
alt="Responsive image with art direction"
width="400"
height="300">
</picture>
< source srcset = " image.webp " type = " image/webp " >
< source srcset = " image.jpg " type = " image/jpeg " >
< img src = " image.jpg " alt = " Description " >
The browser evaluates <source> elements in order from top to bottom:
Checks each <source> element’s media, type, and srcset attributes
Uses the first matching source
Falls back to the <img> element if no source matches
The <img> element displays the selected source and provides the alt text
Art direction allows you to serve different crops or compositions based on viewport size:
Interactive code playground requires JavaScript. Here's the code:
<picture>
<!-- Desktop: wide landscape -->
<source media="(min-width: 1000px)"
srcset="https://picsum.photos/1200/400">
<!-- Tablet: medium crop -->
<source media="(min-width: 600px)"
srcset="https://picsum.photos/800/500">
<!-- Mobile: portrait crop -->
<img src="https://picsum.photos/400/600"
alt="Art direction example: different crops for different screens"
style="width: 100%; height: auto;">
</picture>
<p>Resize your browser to see different image crops</p>
Interactive code playground requires JavaScript. Here's the code:
<picture>
<!-- Large screens: full hero with text space -->
<source media="(min-width: 1200px)"
srcset="https://picsum.photos/1600/600">
<!-- Medium screens: tighter crop -->
<source media="(min-width: 768px)"
srcset="https://picsum.photos/1200/700">
<!-- Small screens: square crop -->
<img src="https://picsum.photos/600/600"
alt="Hero banner adapting to screen size"
style="width: 100%; height: auto; display: block;">
</picture>
Serve modern formats like AVIF and WebP with JPEG/PNG fallbacks:
Interactive code playground requires JavaScript. Here's the code:
<picture>
<!-- Modern browsers: AVIF (best compression) -->
<source srcset="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800&fm=avif&q=80"
type="image/avif">
<!-- Widely supported: WebP -->
<source srcset="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800&fm=webp&q=80"
type="image/webp">
<!-- Universal fallback: JPEG -->
<img src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800&fm=jpg&q=80"
alt="Mountain landscape with modern format support"
width="800"
height="600"
style="width: 100%; height: auto;">
</picture>
Format savings:
AVIF: ~50% smaller than JPEG
WebP: ~30% smaller than JPEG
Both maintain better quality at smaller sizes
Interactive code playground requires JavaScript. Here's the code:
<picture>
<!-- Modern browsers: scalable SVG -->
<source srcset="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'><circle cx='100' cy='100' r='80' fill='%233b82f6'/><text x='100' y='110' text-anchor='middle' fill='white' font-size='40' font-family='Arial'>SVG</text></svg>"
type="image/svg+xml">
<!-- Fallback: PNG -->
<img src="https://via.placeholder.com/200/3b82f6/ffffff?text=PNG"
alt="Logo"
width="200"
height="200">
</picture>
You can use both art direction and format fallbacks together:
Interactive code playground requires JavaScript. Here's the code:
<picture>
<!-- Desktop: wide AVIF -->
<source media="(min-width: 1000px)"
srcset="https://images.unsplash.com/photo-1469474968028-56623f02e42e?w=1200&h=400&fit=crop&fm=avif&q=80"
type="image/avif">
<source media="(min-width: 1000px)"
srcset="https://images.unsplash.com/photo-1469474968028-56623f02e42e?w=1200&h=400&fit=crop&fm=webp&q=80"
type="image/webp">
<!-- Tablet: medium AVIF -->
<source media="(min-width: 600px)"
srcset="https://images.unsplash.com/photo-1469474968028-56623f02e42e?w=800&h=500&fit=crop&fm=avif&q=80"
type="image/avif">
<source media="(min-width: 600px)"
srcset="https://images.unsplash.com/photo-1469474968028-56623f02e42e?w=800&h=500&fit=crop&fm=webp&q=80"
type="image/webp">
<!-- Mobile fallback: JPEG -->
<img src="https://images.unsplash.com/photo-1469474968028-56623f02e42e?w=600&h=600&fit=crop&fm=jpg&q=80"
alt="Nature scene optimized for all devices"
style="width: 100%; height: auto;">
</picture>
Use srcset in <source> elements for resolution switching:
Interactive code playground requires JavaScript. Here's the code:
<picture>
<!-- Desktop: multiple resolutions -->
<source media="(min-width: 1000px)"
srcset="https://picsum.photos/1200/600 1x,
https://picsum.photos/2400/1200 2x">
<!-- Tablet: multiple resolutions -->
<source media="(min-width: 600px)"
srcset="https://picsum.photos/800/500 1x,
https://picsum.photos/1600/1000 2x">
<!-- Mobile: multiple resolutions -->
<img src="https://picsum.photos/400/400"
srcset="https://picsum.photos/400/400 1x,
https://picsum.photos/800/800 2x"
alt="High-DPI responsive image"
style="width: 100%; height: auto;">
</picture>
< source media = " (min-width: 1200px) " srcset = " large.jpg " >
< source media = " (min-width: 768px) " srcset = " medium.jpg " >
< source media = " (min-width: 480px) " srcset = " small.jpg " >
< img src = " tiny.jpg " alt = " Description " >
< source media = " (orientation: landscape) "
< source media = " (orientation: portrait) "
< img src = " landscape.jpg " alt = " Description " >
< source media = " (min-resolution: 2dppx) "
< img src = " standard-res.jpg " alt = " Description " >
< source media = " (prefers-color-scheme: dark) "
< source media = " (prefers-color-scheme: light) "
srcset = " light-theme.jpg " >
< img src = " light-theme.jpg " alt = " Description " >
Interactive code playground requires JavaScript. Here's the code:
<style>
body { background: white; color: black; }
@media (prefers-color-scheme: dark) {
body { background: #1a1a1a; color: white; }
}
</style>
<picture>
<source media="(prefers-color-scheme: dark)"
srcset="https://via.placeholder.com/400x200/1a1a1a/ffffff?text=Dark+Mode">
<img src="https://via.placeholder.com/400x200/ffffff/000000?text=Light+Mode"
alt="Theme-aware image"
width="400"
height="200">
</picture>
<p>Toggle your system dark mode to see the image change</p>
Combine sizes with srcset for sophisticated responsive behavior:
Interactive code playground requires JavaScript. Here's the code:
<picture>
<!-- Large screens: 50% width -->
<source media="(min-width: 1000px)"
srcset="https://picsum.photos/600/400 600w,
https://picsum.photos/800/533 800w,
https://picsum.photos/1000/667 1000w"
sizes="50vw">
<!-- Medium screens: 75% width -->
<source media="(min-width: 600px)"
srcset="https://picsum.photos/450/400 450w,
https://picsum.photos/600/533 600w,
https://picsum.photos/800/711 800w"
sizes="75vw">
<!-- Small screens: full width -->
<img src="https://picsum.photos/400/400"
srcset="https://picsum.photos/400/400 400w,
https://picsum.photos/600/600 600w"
sizes="100vw"
alt="Complex responsive image"
style="width: 100%; height: auto;">
</picture>
Interactive code playground requires JavaScript. Here's the code:
<picture>
<source srcset="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800&fm=webp&q=80"
type="image/webp">
<img src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800&fm=jpg&q=80"
alt="Lazy loaded picture"
width="800"
height="600"
loading="lazy"
style="width: 100%; height: auto;">
</picture>
<p>The loading="lazy" attribute on img applies to the entire picture element</p>
Note
Apply loading, width, height, and other attributes to the <img> element, not to <picture> or <source>.
Interactive code playground requires JavaScript. Here's the code:
<style>
.hero { position: relative; }
.hero img { width: 100%; height: auto; display: block; }
.hero-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-size: 2rem;
text-shadow: 2px 2px 4px rgba(0,0,0,0.8);
}
</style>
<div class="hero">
<picture>
<source media="(min-width: 1000px)"
srcset="https://picsum.photos/1600/500">
<source media="(min-width: 600px)"
srcset="https://picsum.photos/1000/600">
<img src="https://picsum.photos/600/600"
alt="Hero banner">
</picture>
<div class="hero-text">Welcome</div>
</div>
Interactive code playground requires JavaScript. Here's the code:
<style>
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
.product-grid picture img {
width: 100%;
height: auto;
border-radius: 8px;
}
</style>
<div class="product-grid">
<picture>
<source srcset="https://picsum.photos/400/400?random=1&fm=webp"
type="image/webp">
<img src="https://picsum.photos/400/400?random=1"
alt="Product 1" loading="lazy">
</picture>
<picture>
<source srcset="https://picsum.photos/400/400?random=2&fm=webp"
type="image/webp">
<img src="https://picsum.photos/400/400?random=2"
alt="Product 2" loading="lazy">
</picture>
<picture>
<source srcset="https://picsum.photos/400/400?random=3&fm=webp"
type="image/webp">
<img src="https://picsum.photos/400/400?random=3"
alt="Product 3" loading="lazy">
</picture>
</div>
Interactive code playground requires JavaScript. Here's the code:
<style>
.card {
padding: 2rem;
border-radius: 12px;
position: relative;
overflow: hidden;
min-height: 200px;
}
.card picture {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
}
.card img {
width: 100%;
height: 100%;
object-fit: cover;
opacity: 0.3;
}
.card-content {
position: relative;
z-index: 1;
}
</style>
<div class="card">
<picture>
<source media="(min-width: 800px)"
srcset="https://picsum.photos/1200/400">
<img src="https://picsum.photos/600/400"
alt="">
</picture>
<div class="card-content">
<h3>Card with Background Image</h3>
<p>Picture element as background</p>
</div>
</div>
Use <picture> when you need:
Art direction : Different image compositions for different screen sizes
Format fallbacks : AVIF/WebP with JPEG/PNG fallback
Media queries : Complex conditions based on viewport, orientation, or preferences
Different aspect ratios : Square on mobile, landscape on desktop
Interactive code playground requires JavaScript. Here's the code:
<!-- Picture: Different crops -->
<picture>
<source media="(min-width: 800px)"
srcset="landscape-crop.jpg">
<img src="portrait-crop.jpg" alt="Art direction example">
</picture>
Use <img srcset> when you need:
Resolution switching : Same image, different sizes/resolutions
Simpler syntax : No art direction needed
Browser optimization : Let browser choose based on viewport and pixel density
Interactive code playground requires JavaScript. Here's the code:
<!-- img srcset: Same image, different resolutions -->
<img src="photo-400.jpg"
srcset="photo-400.jpg 400w,
photo-800.jpg 800w,
photo-1200.jpg 1200w"
sizes="(max-width: 600px) 100vw, 50vw"
alt="Resolution switching example">
<!-- Different crops for mobile/desktop -->
< source media = " (min-width: 768px) "
< img src = " square-hero.jpg " alt = " Hero " >
<!-- Modern format with fallback -->
< source srcset = " image.avif " type = " image/avif " >
< source srcset = " image.webp " type = " image/webp " >
< img src = " image.jpg " alt = " Photo " >
<!-- Same image, multiple resolutions -->
srcset = " photo-400.jpg 400w,
sizes = " (max-width: 600px) 100vw, 800px "
<!-- Pixel density switching -->
Always provide alt text on the <img> element, not on <source>:
< source srcset = " image.webp " type = " image/webp " >
< img src = " image.jpg " alt = " Descriptive alt text " >
< source srcset = " image.webp " type = " image/webp " alt = " Wrong " >
Interactive code playground requires JavaScript. Here's the code:
<figure>
<picture>
<source media="(min-width: 600px)"
srcset="https://picsum.photos/800/400">
<img src="https://picsum.photos/400/400"
alt="Mountain landscape at sunset"
style="width: 100%; height: auto;">
</picture>
<figcaption>
Mountain peaks during golden hour in the Alps
</figcaption>
</figure>
Order sources by specificity - Most specific first, most general last
Use modern formats - AVIF and WebP can save 30-50% bandwidth
Lazy load - Add loading="lazy" to the <img> element
Set dimensions - Always include width and height on <img>
Optimize all versions - Compress every image variant
Test fallbacks - Ensure JPEG/PNG fallbacks work in older browsers
Feature Chrome Firefox Safari Edge <picture>38+ 38+ 9.1+ 13+ AVIF in <picture> 85+ 93+ 16+ 85+ WebP in <picture> 38+ 38+ 14+ 18+ Media queries 38+ 38+ 9.1+ 13+
<!-- Missing img element -->
< source srcset = " image.webp " type = " image/webp " >
<!-- img not last child -->
< img src = " image.jpg " alt = " Photo " >
< source srcset = " image.webp " type = " image/webp " >
<!-- Alt on source instead of img -->
< source srcset = " image.webp " type = " image/webp " alt = " Wrong " >
<!-- Reversed media query order -->
< source media = " (min-width: 400px) " srcset = " small.jpg " >
< source media = " (min-width: 800px) " srcset = " large.jpg " >
< img src = " tiny.jpg " alt = " Photo " >
<!-- Proper structure -->
< source srcset = " image.webp " type = " image/webp " >
< img src = " image.jpg " alt = " Description " >
<!-- Correct order: most specific first -->
< source media = " (min-width: 800px) " srcset = " large.jpg " >
< source media = " (min-width: 400px) " srcset = " small.jpg " >
< img src = " tiny.jpg " alt = " Photo " >
< source srcset = " image.webp " type = " image/webp " >
< img src = " image.jpg " alt = " Descriptive alt text " >
The actual image element that displays within picture.
Learn more →
Defines alternative image sources in picture.
Learn more →
Semantic container for images with captions.
Learn more →