HTML Picture Element Reference
Complete guide to responsive images — art direction, format fallbacks (AVIF/WebP), srcset, sizes, and performance best practices
Your hero image is a 2MB JPEG. You have AVIF and WebP versions that are 200KB, but Safari only recently added AVIF support and IE11 (yes, some clients still use it) needs JPEG. You also need different crops — landscape for desktop, square for tablet, portrait for mobile. That’s format negotiation + art direction + resolution switching in one <picture> element, and the srcset/sizes/media/type attribute combinations are hard to get right without a reference.
Why This Reference (Not MDN or a CSS-Only Approach)
MDN splits <picture>, srcset, sizes, and art direction across multiple pages. CSS background-image with image-set() handles format negotiation but not semantic images (no alt text, no SEO). This reference covers the complete <picture> pattern — format fallbacks (AVIF → WebP → JPEG), resolution switching with srcset/sizes, art direction with media, lazy loading, CLS prevention, and accessibility — all on one page with copy-ready code examples.
HTML Picture Element Reference
The <picture> element is the browser-native solution for responsive images. It lets you serve different image formats, sizes, and compositions to different browsers and viewport sizes — all with a single HTML declaration and no JavaScript required.
<!-- The complete responsive image pattern: format + resolution -->
<picture>
<source
type="image/avif"
srcset="hero-800.avif 800w, hero-1600.avif 1600w"
sizes="(max-width: 768px) 100vw, 1200px"
/>
<source
type="image/webp"
srcset="hero-800.webp 800w, hero-1600.webp 1600w"
sizes="(max-width: 768px) 100vw, 1200px"
/>
<img
src="hero-1600.jpg"
srcset="hero-800.jpg 800w, hero-1600.jpg 1600w"
sizes="(max-width: 768px) 100vw, 1200px"
alt="Hero banner image"
width="1600"
height="900"
fetchpriority="high"
/>
</picture>
The picture Element Structure
The <picture> element is a container — it has no visual representation of its own. Inside it, you place:
<source>elements (zero or more) — candidate image sources the browser evaluates in order<img>element (required, must be last) — the fallback and the rendered element
<picture>
<!-- Sources: browser evaluates top-to-bottom -->
<source srcset="image.avif" type="image/avif" />
<source srcset="image.webp" type="image/webp" />
<!-- img: required fallback and rendering target -->
<img src="image.jpg" alt="Description" width="800" height="600" />
</picture>
The browser evaluates each <source> from top to bottom and selects the first one whose media query matches the current viewport and whose type is a supported format. If no source matches, the browser uses the <img> element’s src.
Format Fallbacks with the type Attribute
Use the type attribute on <source> with a MIME type string to specify which format each source provides. The browser skips any source whose format it doesn’t support.
<picture>
<source srcset="photo.avif" type="image/avif" /> <!-- Chrome 85+, Firefox 93+, Safari 16+ -->
<source srcset="photo.webp" type="image/webp" /> <!-- All modern browsers -->
<img src="photo.jpg" alt="Photo" /> <!-- Universal fallback -->
</picture>
Format Comparison
| Format | Compression | Alpha | Animation | Browser Support |
|---|---|---|---|---|
| AVIF | Best | Yes | Yes | Chrome 85+, Firefox 93+, Safari 16+ |
| WebP | Very Good | Yes | Yes | Chrome 32+, Firefox 65+, Safari 14+ |
| JPEG | Good | No | No | All browsers |
| PNG | Lossless | Yes | No | All browsers |
Always order sources from most efficient to least efficient: AVIF → WebP → JPEG/PNG.
Art Direction with the media Attribute
Use the media attribute on <source> with a CSS media query to serve different image compositions at different viewport sizes. This is art direction — completely different image crops or subjects per breakpoint.
<picture>
<!-- Desktop: wide panoramic crop -->
<source
media="(min-width: 1024px)"
srcset="banner-wide.webp"
type="image/webp"
/>
<!-- Tablet: medium crop -->
<source
media="(min-width: 600px)"
srcset="banner-medium.webp"
type="image/webp"
/>
<!-- Mobile: tight portrait crop (img fallback) -->
<img src="banner-portrait.jpg" alt="Banner image" width="400" height="600" />
</picture>
Art direction solves the problem of a wide landscape photo showing the subject as a tiny dot on a mobile screen. Prepare multiple crops during content authoring and serve the right one per viewport.
srcset and sizes for Resolution Switching
Resolution switching provides the same image at multiple resolutions, letting the browser pick the right one for the device’s pixel density and viewport size.
Width Descriptors (w)
<img
srcset="image-400w.jpg 400w,
image-800w.jpg 800w,
image-1600w.jpg 1600w"
sizes="(max-width: 480px) 100vw,
(max-width: 900px) 50vw,
800px"
src="image-1600w.jpg"
alt="Responsive image"
width="800"
height="600"
/>
The sizes attribute tells the browser how wide the image will be rendered at each viewport breakpoint. The browser uses this to calculate which srcset candidate to fetch, accounting for the device pixel ratio (DPR).
Density Descriptors (x)
For fixed-size UI elements like icons and avatars, use density descriptors instead:
<img
src="avatar-64.jpg"
srcset="avatar-64.jpg 1x, avatar-128.jpg 2x, avatar-192.jpg 3x"
alt="User avatar"
width="64"
height="64"
/>
No sizes attribute is needed with density descriptors — the browser picks based solely on window.devicePixelRatio.
Lazy Loading
Apply loading="lazy" to images that start below the fold to defer their fetch until they are near the viewport:
<!-- Above the fold: DO NOT lazy-load -->
<picture>
<source srcset="hero.webp" type="image/webp" />
<img src="hero.jpg" alt="Hero" loading="eager" fetchpriority="high" />
</picture>
<!-- Below the fold: lazy-load safely -->
<picture>
<source srcset="article-photo.webp" type="image/webp" />
<img
src="article-photo.jpg"
alt="Article photo"
loading="lazy"
width="800"
height="500"
/>
</picture>
Critical rule: Never use loading="lazy" on the above-the-fold hero image — it directly delays the Largest Contentful Paint (LCP) metric.
Preventing CLS with width and height
Cumulative Layout Shift (CLS) from images occurs when the browser doesn’t know the image dimensions until it starts downloading. Adding width and height attributes solves this:
<picture>
<source srcset="product.webp" type="image/webp" />
<!-- width + height let the browser reserve space before load -->
<img
src="product.jpg"
alt="Product photo"
width="600"
height="400"
style="width: 100%; height: auto;"
/>
</picture>
The browser uses width and height to calculate the aspect ratio and injects aspect-ratio: 600/400 via its user-agent stylesheet — reserving the correct space immediately. CSS still controls the rendered size.
LCP Image Optimization
For the Largest Contentful Paint image:
<!-- Preload in <head> for the fastest possible discovery -->
<link
rel="preload"
as="image"
href="hero.jpg"
imagesrcset="hero-800.jpg 800w, hero-1600.jpg 1600w"
imagesizes="100vw"
/>
<!-- In <body>: the LCP image with high priority -->
<picture>
<source srcset="hero.avif" type="image/avif" />
<source srcset="hero.webp" type="image/webp" />
<img
src="hero.jpg"
alt="Hero banner"
width="1600"
height="900"
fetchpriority="high"
loading="eager"
/>
</picture>
The fetchpriority="high" attribute signals the browser to prioritize this image’s download over other resources.
Accessibility
alt Text
Every <img> inside <picture> must have an alt attribute. Screen readers announce it when focus reaches the image.
<!-- Informational image: descriptive alt -->
<img src="chart.jpg" alt="Bar chart showing 40% YoY growth in Q3 2024" />
<!-- Decorative image: empty alt (tells screen readers to skip it) -->
<img src="divider.png" alt="" />
figure and figcaption
Wrap <picture> in <figure> with a <figcaption> for images that need a visible caption:
<figure>
<picture>
<source srcset="sunset.avif" type="image/avif" />
<img src="sunset.jpg" alt="Orange sunset over the Pacific Ocean" width="1200" height="800" />
</picture>
<figcaption>Sunset at Ocean Beach, San Francisco. Photo: Jane Doe, CC BY 4.0.</figcaption>
</figure>
The figcaption supplements the alt text — do not use identical text for both.
Browser Support
The <picture> element is Baseline 2018:
| Browser | Since |
|---|---|
| Chrome | 38 |
| Firefox | 38 |
| Safari | 9.1 |
| Edge | 13 |
Format support:
| Format | Chrome | Firefox | Safari |
|---|---|---|---|
| AVIF | 85 | 93 | 16 |
| WebP | 32 | 65 | 14 |
Common Mistakes
Missing <img> fallback: The <img> element is required inside <picture>. Omitting it makes the element render nothing in all browsers.
Using media instead of type for format selection: The media attribute evaluates CSS media queries — it cannot detect format support. Use type="image/avif" for AVIF, type="image/webp" for WebP.
Wrong source order: Sources are evaluated top-to-bottom. If JPEG appears first, every browser picks it and the more efficient AVIF/WebP sources are never used.
Missing alt attribute: All <img> elements must have alt — descriptive text for informational images, empty string alt="" for decorative ones.
Lazy-loading the LCP image: loading="lazy" delays the LCP image and directly hurts Core Web Vitals scores. Only lazy-load images that start below the fold.
FAQ
When should I use <picture> vs just <img> with srcset?
Use <picture> when you need art direction (different image crops per viewport via media) or format fallbacks (AVIF/WebP via type). Use plain <img> with srcset and sizes for resolution switching where the same image composition is served at multiple resolutions — it’s simpler and works equally well.
Do I need to include a JPEG fallback in picture?
Yes. The <img> src attribute is the universal fallback for browsers that don’t support <picture> (rare today) or when no <source> matches. Always use the most compatible format (JPEG or PNG) as the img src.
Can I combine art direction and format fallbacks in one picture element?
Yes — add both media and type attributes to the same <source> element. List sources from most efficient format to least, grouped by art direction breakpoint: desktop AVIF → desktop WebP → desktop JPEG, then mobile AVIF → mobile WebP, with the <img> providing the mobile JPEG fallback.
How do I pick the right sizes values?
Open your page in Chrome DevTools, check the rendered image width at different viewport sizes, and translate those measurements into sizes media condition + length pairs. Incorrect sizes values cause the browser to fetch an image that’s too large or too small. Lighthouse’s “Properly size images” audit will flag significant mismatches.
Does lazy loading work with picture elements?
Yes — apply loading="lazy" on the <img> element inside <picture>. The attribute affects the image fetch regardless of which <source> the browser selects. Remember: never lazy-load the above-the-fold hero image.
What is fetchpriority and when should I use it?
fetchpriority="high" is a hint that bumps the image’s download priority above other resources. Apply it to the LCP hero image — typically the largest above-the-fold image. Only apply it to one image per page; using it on multiple images cancels out the benefit.