Modern Image Formats: AVIF and WebP

WebPerformanceImagesFrontend
Share on LinkedIn

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

  1. Convert images to AVIF and WebP at build time
  2. Use <picture> with format fallbacks
  3. Add responsive srcset and sizes
  4. Set explicit width and height to prevent CLS
  5. Preload LCP image, lazy-load everything else
  6. 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.

Measuring success in production

Deploy changes behind feature flags when possible so you can compare metrics between control and treatment groups. Use Real User Monitoring to capture performance data from actual devices and network conditions — lab tools alone miss the long tail of user experiences. Set up alerts for regressions: a 10% LCP increase week-over-week warrants investigation before it hits CrUX.

Document your baseline metrics before making changes. Performance work without measurement is guesswork. Share results with the team — concrete numbers ("LCP improved 800ms on mobile") build support for continued investment in web performance and reliability.

Review changes quarterly. Browser updates, new API support, and traffic pattern shifts can obsolete previous optimizations or create new opportunities. What worked in 2024 may not be the best approach in 2026.

Additional production considerations

Teams often underestimate the maintenance cost of performance optimizations. Automate what you can: CI bundle budgets, Lighthouse CI on PRs, and RUM dashboards that alert on regressions. Manual audits don't scale past a handful of pages.

Security and performance intersect more than teams expect. Third-party scripts that hurt INP also expand your attack surface. Self-hosting fonts and critical assets reduces both latency and supply-chain risk. Review every external dependency quarterly — remove what you no longer need.

Accessibility and performance share goals: semantic HTML helps screen readers and gives the browser better rendering hints. Native elements like dialog, popover, and details reduce JavaScript while improving accessibility. Prefer platform features over custom implementations when they meet your requirements.

Mobile users dominate traffic for most sites. Test on real mid-tier Android hardware, not just desktop Chrome. Simulated throttling in DevTools approximates network conditions but not CPU constraints. A fix that helps desktop may be invisible on mobile if the bottleneck is JavaScript execution, not network.

Collaborate with backend teams on TTFB and API response times. Frontend optimizations can't fix a 2-second server response. Set SLAs for API endpoints that feed critical pages and measure them in the same RUM pipeline as Core Web Vitals.

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.

Resources

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 →