10.4 Converting to WebP and AVIF
Right, let’s talk about making your images stop clogging the internet’s pipes. You’ve got your PNGs and JPEGs, the old warhorses. They work. They’re also, by modern standards, hilariously inefficient. Serving a 2MB JPEG in 2023 is like showing up to a drone race with a carrier pigeon—it gets the job done, but everyone is judging you.
We’re converting those hefty files to WebP and AVIF. Why both? Because while WebP is the established, widely-supported champion, AVIF is the new kid on the block who’s somehow even better at compression. Your goal is to serve AVIF to browsers that understand it (they’ll thank you with blazing fast loads) and provide WebP as a solid fallback for everyone else. The process isn’t magic, it’s just a bit of command-line (or script) wrangling.
The Core Conversion Commands
First, you’ll need the right tools. For WebP, that’s cwebp and dwebp from Google’s libwebp package. For AVIF, it’s a bit more fragmented, but the most robust encoder I’ve found is avifenc from the libavif library. Install them via your package manager (brew install webp libavif on Mac, apt install webp and then build libavif from source on Ubuntu, because of course the best AVIF tool isn’t in the main repos yet).
Here’s how you convert a basic JPEG to a decent WebP:
cwebp -q 80 input_image.jpg -o output_image.webp
The -q flag is quality, on a scale of 0-100. 80 is the sweet spot where you get massive file size savings with virtually no perceptible loss. Don’t just blindly use 100; you’re missing the point.
For AVIF, the command is similar but with more knobs because it’s a newer format:
avifenc -c aom -s 6 -j 4 --min 0 --max 63 -q 80 input_image.jpg output_image.avif
Let’s unpack this:
-c aom: Use the AO1M encoder (the best one).-s 6: Speed setting. 0 is slowest (best compression), 10 is fastest. 6 is a good default. For a production batch job, crank this to 0 and let it run overnight.-j 4: Use 4 CPU threads. Use all the cores your machine has.--min 0 --max 63: Set the quantizer range. 0 is lossless, 63 is worst quality. Using a fixed-q 80is often easier, but this fine-grained control is why AVIF wins.
Why This Actually Works (The Nerd Stuff)
JPEG is basically built on cosine transforms, a mathematical technique from the 90s. WebP and AVIF use more modern codecs (VP8/VP9 and AV1, respectively) that are descendants of the video world’s brutal efficiency wars. They can do things like predict pixels from surrounding areas, allowing them to describe the same visual information with far less data. AVIF, being based on AV1, is the most advanced here. It often produces files 30-50% smaller than WebP at the same quality. The downside? Encoding is brutally slow. It’s a trade-off: burn CPU cycles once on your server to save bandwidth and load time for every single user forever.
The Gotchas and Gray Areas
Transparency? WebP and AVIF handle it beautifully, unlike JPEG which just gives up. But be warned: converting a PNG-24 with transparency to WebP is fine, but if you have a simple PNG-8 with a 1-bit transparency palette, cwebp might produce a larger file. It’s optimising for a different use case.
Animation? Both formats support it. You can convert GIFs to animated WebP (img2webp tool) or animated AVIF for staggering file size reductions. That 500KB annoying cartoon GIF becomes a 80KB WebP. You’re welcome.
The biggest pitfall is not checking browser support in your HTML. There’s no point in serving these modern marvels if you don’t do it right. Use the <picture> element. Always.
<picture>
<source srcset="image.avif" type="image/avif">
<source srcset="image.webp" type="image/webp">
<img src="image.jpg" alt="A description of the image">
</picture>
This tells the browser “Hey, if you speak AVIF, use this. No? Okay, what about WebP? Still no? Fine, here’s the JPEG.” It’s progressive enhancement at its finest. The <img> tag is your mandatory, no-JS fallback.
Batch Processing: Your New Best Friend
You’re not doing this one image at a time. Use a bash for loop or write a simple Node/Python script. Here’s a quick and dirty bash example to convert all JPEGs in a directory:
# Convert to WebP
for file in *.jpg; do cwebp -q 80 "$file" -o "${file%.jpg}.webp"; done
# Convert to AVIF (assuming avifenc is installed)
for file in *.jpg; do avifenc -c aom -s 6 -j 4 -q 80 "$file" "${file%.jpg}.avif"; done
For a real project, you’d want something more robust that handles errors, doesn’t reconvert existing files, and maybe even integrates into your build process (looking at you, Webpack and Gulp plugins).
The bottom line? Converting your image pipeline is one of the highest ROI performance optimizations you can make. It’s a bit of upfront work that pays off in reduced bandwidth bills, faster page loads, and happier users. And frankly, your carrier pigeons deserve a rest.