You know that WebP and AVIF produce smaller files than JPG. The question is how to serve them without breaking anything. The answer involves the <picture> element, content negotiation, build pipelines, and a bit of pragmatism about when each approach makes sense.
This guide is for developers who want to implement modern image formats correctly, not just convert a few files.
The Format Landscape in 2026
| Format | Compression | Browser support | Best for |
|---|---|---|---|
| JPEG | Lossy, 8-bit | 100% | Legacy fallback, email, social sharing |
| PNG | Lossless, 8-bit, alpha | 100% | Graphics, screenshots, transparency (when WebP not viable) |
| WebP | Lossy/lossless, 8-bit, alpha, animation | 97% | Default web format, dynamic pipelines |
| AVIF | Lossy/lossless, 10/12-bit, alpha, HDR | 93% | Maximum compression, photography, static assets |
The practical stack in 2026: AVIF first, WebP fallback, JPEG last resort. This covers 100% of browsers while giving 93% of users the best compression available.
Implementing <picture> with Multiple Sources
The <picture> element is the standard way to serve multiple formats. The browser evaluates <source> elements top to bottom and downloads only the first one it supports:
<picture>
<source srcset="hero.avif" type="image/avif">
<source srcset="hero.webp" type="image/webp">
<img src="hero.jpg" alt="Description" width="1200" height="600">
</picture>
Combine with srcset for responsive images:
<picture>
<source
srcset="hero-400.avif 400w, hero-800.avif 800w, hero-1200.avif 1200w"
sizes="(max-width: 600px) 100vw, (max-width: 1200px) 80vw, 1200px"
type="image/avif">
<source
srcset="hero-400.webp 400w, hero-800.webp 800w, hero-1200.webp 1200w"
sizes="(max-width: 600px) 100vw, (max-width: 1200px) 80vw, 1200px"
type="image/webp">
<img
src="hero-800.jpg"
alt="Description"
width="1200"
height="600"
fetchpriority="high"
>
</picture>
Key points:
- List AVIF before WebP. The browser picks the first match.
- The
typeattribute is mandatory. Without it, the browser cannot determine format support. - Always include
widthandheighton the<img>to prevent layout shift (CLS). - Use
fetchpriority="high"on the LCP image,loading="lazy"on below-fold images. - The
sizesattribute must be identical across all<source>elements and the<img>.
Server-Side Content Negotiation via Accept Header
Content negotiation serves the right format from a single URL. The browser sends an Accept header listing the formats it supports, and the server responds with the best match.
A typical modern browser sends:
Accept: image/avif, image/webp, image/png, image/jpeg, */*
Nginx configuration:
map $http_accept $webp_suffix {
default "";
"~*image/webp" ".webp";
}
map $http_accept $avif_suffix {
default "";
"~*image/avif" ".avif";
}
location ~* \.(jpg|jpeg|png)$ {
# Try AVIF first, then WebP, then the original
try_files $uri$avif_suffix $uri$webp_suffix $uri =404;
add_header Vary Accept;
}
Important: always return Vary: Accept when the response depends on the Accept header. Without it, caches and CDNs may serve the wrong format to the wrong browser.
Advantages of content negotiation:
- Simpler HTML, just a single
<img>tag. - Works with CSS
background-image. - No client-side JavaScript needed.
Disadvantages:
- Requires server configuration.
- Harder to debug (the same URL returns different content).
- Does not work with static hosting that does not support
try_filesor equivalent.
CDN-Level Format Negotiation
Most modern CDNs support automatic image format negotiation, which combines the benefits of content negotiation without requiring origin server changes:
Cloudflare: Polish + WebP/AVIF conversion in the Cloudflare dashboard. Enabled per zone, no code changes needed. Cloudflare reads the Accept header and serves the appropriate format from its cache.
AWS CloudFront + Lambda@Edge: write a Lambda function that rewrites the request URI based on the Accept header, pointing to pre-generated AVIF/WebP variants on S3.
Fastly: use VCL to inspect req.http.Accept and modify req.url or set a cache variation key.
CDN-level negotiation is the lowest-effort approach for existing sites. The origin serves JPEG, the CDN converts or selects the right variant, and the client gets AVIF or WebP automatically.
Build Pipeline Integration
For static sites and build-step workflows, generate all format variants at build time:
Using the Morphix API in a build script:
#!/bin/bash
for file in src/images/*.{jpg,jpeg,png}; do
[ -f "$file" ] || continue
name=$(basename "${file%.*}")
for format in webp avif; do
curl -s -X POST https://morphix.tools/api/v1/convert \
-H "Authorization: Bearer $MORPHIX_API_KEY" \
-F "file=@$file" \
-F "format=$format" \
-F "quality=80" \
--output "dist/images/$name.$format"
done
cp "$file" "dist/images/"
done
This produces three files per source image: original, WebP, and AVIF. Your HTML template then uses <picture> to reference all three.
Framework integration:
- Next.js: the built-in
<Image>component handles WebP/AVIF negotiation automatically via its image optimization API. - Astro: the
<Image>component generates optimized formats at build time. - Gatsby:
gatsby-plugin-imagewith Sharp generates WebP variants automatically. - Static HTML: use a build script as shown above, or a task runner like Make.
Testing and Validation
After implementation, validate that the right format is being served:
Browser DevTools. Open the Network tab, load the page, and check the Content-Type header of each image response. It should show image/avif, image/webp, or image/jpeg depending on your browser and configuration.
Test with different browsers. If you use content negotiation, test with a browser that does not support AVIF (or temporarily disable AVIF support in DevTools) to verify that the WebP fallback works.
Check for Vary: Accept. If you use server-side content negotiation, verify that the Vary: Accept header is present. Without it, CDN caches may serve AVIF to a browser that only supports JPEG.
Lighthouse. Run Lighthouse and check the "Serve images in next-gen formats" audit. It should pass if you are serving WebP or AVIF.
Visual comparison. Open the same page with and without format conversion and compare visual quality. At quality 80, the difference should be invisible.
Convert Your Images
Morphix converts JPG and PNG images to WebP and AVIF directly in your browser, or at scale via the API. No registration required for the free plan.