zachleat’s Ugly Mug

Zach Leatherman

Wait, WebP is actually worth it.

30 April 2017 Read this in about 5 minutes.

For my previous talk, I decided to do something a little different with my slides—I decided to self host them.

When I work on a talk, I create the slides in Keynote. After the talk has finished, I’ll post them on Speakerdeck. Speakerdeck is very ok. It operates how I’d expect a shallow copy of a dynamic slideshow to operate. I wanted to try to do a little better.

I definitely like the format, perhaps pioneered (at least in my experience) by Maciej Cegłowski. It’s a big giant two column format with slide images on the left and presenter notes on the right. I’ve also seen this done beautifully by Scott Jehl on the Filament Group lab.

So I dug deep into the Filament Group Slack archives and found a tool to generate images from Keynote slides, called Keynote Extractor. It works quite well. It extracted my Keynote slides into a simple directory with HTML, CSS, and PNG image files. The only problem was that the images were huge—a total of almost 18MB to be exact.

Devtools Screenshot showing 18MB download

ImageOptim

Okay, so maybe the images aren’t properly optimized. Let’s run them through ImageOptim and see how much that helps.

Devtools Screenshot showing 12MB download

Okay, 12MB—that’s an improvement, but obviously not good enough.

JPEG

Let’s convert the PNG images to JPEG. JPEG compression is magical and often better for realistic photos.

# Converts a directory of PNG files to JPG
# Added this to my .zshrc file (or .bash_profile)
# Install `imagemagick` with `brew install imagemagick`
function batchjpeg() {
	for i in *.png
	do
		convert "$i" "${i%.*}.jpg"
	done
}
Devtools Screenshot showing 4.5MB download

Getting better—4.5MB.

WebP

I must admit that I’ve carried a bias against WebP and thought it was a little silly in the past, mostly because it had limited browser support, which necessitated a JavaScript solution or a backend service to serve WebP images properly with fallbacks.

Then I ran across this tweet (thanks Eric!) a few days ago and decided to re-evaluate my position.

My initial reaction was leftover angst that pre-dated the <picture> element, which has since expanded to have pretty great browser support. <picture> gives us a simple no JavaScript, no backend way to serve WebP to browsers that support it. Looks like the only mild problem is on Opera Mini and the Android Browser, which support WebP but not <picture>—but they’ll just suffer a mild performance hit and get the JPG fallback.

It’s important to note that I converted the original PNG images to WebP (not from JPG), given that I converted at 80% quality.

# Converts a directory of image files to WebP
# Added this to my .zshrc file (or .bash_profile)
# Install `cwebp` using `brew install webp`
function batchwebp() {
	for file in *
	do
		cwebp -q 80 "$file" -o "${file%.*}.webp"
	done
}
Devtools Screenshot showing 1.5MB download

Wow. From 17.9MB down to 1.5MB total. That’s a 91.6% decrease.

For 52 individual image slides, this is a great result. Especially considering that I didn’t even resize the original images. At their max rendered width (496 pixels at their widest) and with a 1024 pixel natural image width, each image is at minimum 2.064516129x-Retina friendly.

Like Eric Lawrence in his tweet, I would now encourage you to try out WebP with <picture>! Shave off those KB, y’all.

Implementation Note

In the final product you see on my website, I cheated a little bit in that four of the slides are actually videos that only preload the metadata. Video metadata is likely to be a smaller footprint than a full resolution slide image. None of that matters in the analysis above, however—the screenshots were recreated without videos.

More Optimization Possibilities

Here are a few more things I could do to improve this even further if I wanted to expend the time. For this particular project, I don’t, but for professional work I probably would. But perhaps therein lies the danger with WebP. We implement an easy Chrome(-ish) only optimization and call it a day, when really this page needs more optimization for non-WebP browsers.

  • To make the entire slideshow page weight smaller, I could adjust the maximum rendered size of the slides to be smaller. I might even use a minimum of 1.5x-Retina instead of the 2.06x minimum I’m using now.
  • I could also use srcset with <picture> to serve smaller sources at smaller viewport sizes. I’d look to keep the Retina rating somewhat consistent at different viewport sizes.
  • Evaluate a compressive images approach with WebP and super low quality conversion values.
  • I could also look at possible savings from converting the text-only slides to use a webfont instead of an image.
  • Lazy loading the slides with JavaScript, which does not really have a good standards-based way to implement. It would require non-standard markup for the images to hide them from the preparser. That’s what AMP does, last I checked. It’d be a good exercise to think through how this might work with <picture>, too.