Using modern formats like WebP and AVIF with proper fallbacks ensures optimal file sizes while maintaining compatibility.
<picture>
<source
srcset="image.avif"
type="image/avif"
>
<source
srcset="image.webp"
type="image/webp"
>
<img
ngSrc="image.jpg"
width="800"
height="400"
alt="Fallback image"
priority="true"
>
</picture>
Tools like eleventy-img can automatically generate optimized images in multiple formats and sizes during build time:
// Using eleventy-img during build
import Image from "@11ty/eleventy-img";
async function generateImages() {
let src = "hero-image.jpg";
let stats = await Image(src, {
widths: [300, 600, 900],
formats: ["avif", "webp", "jpeg"],
outputDir: "./public/images/"
});
return stats;
}
// Generated HTML:
<picture>
<source
type="image/avif"
srcset="/images/hero-300.avif 300w,
/images/hero-600.avif 600w,
/images/hero-900.avif 900w"
sizes="(max-width: 900px) 100vw, 900px">
<source
type="image/webp"
srcset="/images/hero-300.webp 300w,
/images/hero-600.webp 600w,
/images/hero-900.webp 900w"
sizes="(max-width: 900px) 100vw, 900px">
<img
src="/images/hero-900.jpeg"
srcset="/images/hero-300.jpeg 300w,
/images/hero-600.jpeg 600w,
/images/hero-900.jpeg 900w"
sizes="(max-width: 900px) 100vw, 900px"
loading="lazy"
decoding="async"
alt="Hero image">
</picture>
Compare these modern formats in the Network tab. Notice the significantly smaller file sizes while maintaining the same visual quality:

AVIF version: ~18KB

WebP version: ~34KB