Modern Image Formats: AVIF and WebP
Our product catalog served 400KB JPEG hero images. Converting to AVIF at equivalent visual quality produced 120KB files — a 70% reduction across 2,000 product images. Total page weight on category pages dropped from 4.2MB to 1.4MB. LCP improved by 2.1 seconds on mobile without changing image dimensions or CDN infrastructure.
Format comparison
| Format | Compression | Browser support | Best for |
|---|---|---|---|
| JPEG | Lossy, baseline | Universal | Fallback, photos |
| PNG | Lossless | Universal | Transparency fallback |
| WebP | Lossy + lossless | 97%+ | Middle tier |
| AVIF | Lossy + lossless | 93%+ | Primary format |
Picture element with fallbacks
<picture>
<source srcset="/images/hero-800.avif 800w, /images/hero-1200.avif 1200w"
sizes="(max-width: 768px) 100vw, 1200px" type="image/avif" />
<source srcset="/images/hero-800.webp 800w, /images/hero-1200.webp 1200w"
sizes="(max-width: 768px) 100vw, 1200px" type="image/webp" />
<img src="/images/hero-1200.jpg"
srcset="/images/hero-800.jpg 800w, /images/hero-1200.jpg 1200w"
sizes="(max-width: 768px) 100vw, 1200px"
width="1200" height="675" alt="Product hero" loading="lazy" decoding="async" />
</picture>
The browser picks the first source whose type it supports. JPEG is the universal fallback.
Responsive srcset
Serve appropriately sized images per viewport:
<img src="/photo-800.avif"
srcset="/photo-400.avif 400w, /photo-800.avif 800w, /photo-1200.avif 1200w"
sizes="(max-width: 600px) 100vw, (max-width: 1200px) 50vw, 600px"
width="800" height="600" alt="Description" />
Build-time conversion
Convert during CI with sharp:
import sharp from 'sharp';
await sharp('src/images/hero.jpg')
.avif({ quality: 50, effort: 4 })
.toFile('dist/images/hero.avif');
await sharp('src/images/hero.jpg')
.webp({ quality: 80 })
.toFile('dist/images/hero.webp');
Generate all formats at build time. Serve from static hosting or CDN.
Quality tuning
| Format | Recommended quality | Notes |
|---|---|---|
| AVIF | 45-55 | Lower number = smaller file, quality scale differs |
| WebP | 75-85 | Comparable to JPEG 80-90 |
| JPEG | 80-85 | Fallback baseline |
Compare visually at 100% zoom on retina displays. Automated SSIM comparison tools help batch-tune quality settings.
CDN automatic format negotiation
https://cdn.example.com/cdn-cgi/image/format=auto,quality=80/photo.jpg
The CDN inspects the Accept header and returns the best supported format. No picture element needed.
Lazy loading and priority
Preload the LCP image with <link rel="preload">. Use loading="lazy" for below-the-fold images only. Never lazy-load the LCP candidate.
Checklist
- Convert images to AVIF and WebP at build time
- Use
<picture>with format fallbacks - Add responsive
srcsetandsizes - Set explicit
widthandheightto prevent CLS - Preload LCP image, lazy-load everything else
- Tune quality per format
Art direction with picture
Serve different crops per viewport:
<picture>
<source media="(max-width: 768px)" srcset="/hero-mobile.avif" />
<source media="(min-width: 769px)" srcset="/hero-desktop.avif" />
<img src="/hero-desktop.jpg" alt="Hero" width="1200" height="675" />
</picture>
Combine art direction with format fallbacks using nested picture elements or multiple source tags.
Encoding speed vs. quality
AVIF encoding is slower than WebP or JPEG. Pre-generate at build time — never encode on-the-fly in request path unless using a dedicated image CDN with caching.
Debugging checklist
When something doesn't work as documented, verify browser support with Can I use before assuming a polyfill bug. Check the Network tab for failed resource loads, incorrect MIME types, and missing CORS headers. Use the Console for CSP violations and Trusted Types errors that silently block operations.
Compare behavior in incognito mode to rule out extension interference. Test with cache disabled during development but validate with realistic caching in staging. Read the specification for edge cases the tutorial skipped — MDN examples cover happy paths, not every boundary condition.
If performance regresses after deployment, roll back first and investigate second. Keep a changelog of performance-related changes linked to metric dashboards. Future you will need to know why that preload tag exists before removing it during a refactor.
Screenshot and UI imagery
AVIF lossy compression blurs small text in marketing screenshots—use WebP lossless or PNG for UI captures with text. Photos and hero photography benefit most from AVIF.
Email clients
Most email clients ignore AVIF—serve JPEG in <img> for transactional email; AVIF for web only.
Image CDNs and origin shield
Transform at CDN edge on first request caches AVIF variant at PoP—origin serves single JPEG master. Configure quality rungs (q=45, q=55, q=65) and let CDN negotiate.
picture element cascade
<picture>
<source type="image/avif" srcset="hero.avif" />
<source type="image/webp" srcset="hero.webp" />
<img src="hero.jpg" alt="..." width="1200" height="630" />
</picture>
Always include JPEG fallback for email clients and old Safari. CDN auto-negotiation simplifies markup but test Vary headers cache correctly.
AVIF for UI screenshots
Lossy AVIF blurs small text in product screenshots — use WebP lossless or PNG for UI captures; AVIF for photo heroes.
Practical follow-through (1)
Ship the smallest vertical slice first — one route, one widget, one index configuration — with rollback documented before expanding scope. Baseline the user-visible metric this work protects (latency, recall, conversion, task success rate) for seven days before change and seven days after in your largest market.
Compare canary p75 to control before full rollout. Exercise edge paths manually: refresh, back navigation, double-submit, offline mode, and keyboard-only flows. When assumptions change — traffic doubles, vendor upgrades, org restructure — revisit whether the original design still fits; quiet periods hide drift until the next incident.
Practical follow-through (2)
Ship the smallest vertical slice first — one route, one widget, one index configuration — with rollback documented before expanding scope. Baseline the user-visible metric this work protects (latency, recall, conversion, task success rate) for seven days before change and seven days after in your largest market.
Compare canary p75 to control before full rollout. Exercise edge paths manually: refresh, back navigation, double-submit, offline mode, and keyboard-only flows. When assumptions change — traffic doubles, vendor upgrades, org restructure — revisit whether the original design still fits; quiet periods hide drift until the next incident.
Practical follow-through (3)
Ship the smallest vertical slice first — one route, one widget, one index configuration — with rollback documented before expanding scope. Baseline the user-visible metric this work protects (latency, recall, conversion, task success rate) for seven days before change and seven days after in your largest market.
Compare canary p75 to control before full rollout. Exercise edge paths manually: refresh, back navigation, double-submit, offline mode, and keyboard-only flows. When assumptions change — traffic doubles, vendor upgrades, org restructure — revisit whether the original design still fits; quiet periods hide drift until the next incident.
Practical follow-through (4)
Ship the smallest vertical slice first — one route, one widget, one index configuration — with rollback documented before expanding scope. Baseline the user-visible metric this work protects (latency, recall, conversion, task success rate) for seven days before change and seven days after in your largest market.
Compare canary p75 to control before full rollout. Exercise edge paths manually: refresh, back navigation, double-submit, offline mode, and keyboard-only flows. When assumptions change — traffic doubles, vendor upgrades, org restructure — revisit whether the original design still fits; quiet periods hide drift until the next incident.
Practical follow-through (5)
Ship the smallest vertical slice first — one route, one widget, one index configuration — with rollback documented before expanding scope. Baseline the user-visible metric this work protects (latency, recall, conversion, task success rate) for seven days before change and seven days after in your largest market.
Compare canary p75 to control before full rollout. Exercise edge paths manually: refresh, back navigation, double-submit, offline mode, and keyboard-only flows. When assumptions change — traffic doubles, vendor upgrades, org restructure — revisit whether the original design still fits; quiet periods hide drift until the next incident.
Resources
- web.dev: Choose the right image format
- AVIF browser support (Can I use)
- MDN: picture element
- Squoosh image compression tool
- sharp image processing library
Frequently asked questions
How much smaller are AVIF and WebP compared to JPEG?
AVIF typically achieves 30-50% smaller file sizes than JPEG at equivalent visual quality, and 20-30% smaller than WebP. WebP is 25-35% smaller than JPEG. Actual savings depend on image content — photos with gradients compress well; screenshots with sharp text may see smaller differences. Always compare at matched visual quality, not matched quality settings.
Should I use the picture element or content negotiation?
Use the picture element when you control the HTML and need explicit format fallbacks. Use content negotiation (Accept header) when a CDN or image service automatically serves the best format. Picture element gives you explicit control; CDN negotiation requires zero HTML changes.
Do all browsers support AVIF?
AVIF is supported in Chrome 85+, Firefox 93+, Safari 16+, and Edge 85+ — covering over 93% of global users as of 2026. Always provide WebP and JPEG/PNG fallbacks via the picture element for the remaining browsers. WebP has near-universal support and serves as a safe middle tier.
Hiring a senior Android / Flutter engineer?
I architect and ship production mobile software — Kotlin, Jetpack Compose, Flutter — for robotics, EV infrastructure, fintech, and real-time systems. Open to remote roles in Europe and the US.
Get in touch →