The Move to WebP

Anyone notice that pages are (hopefully) loading a little quicker, especially for ones that contain a bunch of images?

Well I just changed from using PNG image files, to WebP image files. For some more specifics, read on.

WebP

WebP is a Google project, of all things, sister to the WebM project, for highly compressed image files to be used on the web. They can either be lossless or lossy compressed, and use some of the same concepts of video codecs to get some absurdly small file sizes. I’m going to use a post with a bunch of photos, just a bit ago when I talked about white balance.

Average size of PNG files: 2.66 MB Average size of WebP files: 23.72 kB

What.

Support for WebP, and Compatibility

Now this is their major downside: Currently, only the latest Edge versions, as well as Chrome and Opera support WebP (and anything based off the Chrome core), the rest.. just fail. This means, for example, Safari, meaning any Mac users would suddenly see a lot of “I can’t render this” icons instead of images, not cool. So the question becomes, how can I make it compatible?

First, I didn’t get rid of PNGs, every image now has a WebP copy and a PNG copy.

Second, I used a new HTML feature: <picture>

<picture>

<picture> is a new(er) tag in the HTML specification that is kinda supposed to replace the common <img> for embedding images. I won’t go into the whole syntax of it, but all you need to know is that where an image used to be represented like this on my site:

<center>
    <img src="{{ .Destination }}" alt="{{ .Title }}">
</center>

It now looks like this:

<center>
    <picture>
        <source srcset="{{ .Destination }}" type="image/webp">
            <img src="{{ replace .Destination ".webp" ".png" }}" alt="{{ .Title }}">
        </source>
    </picture>
</center>

(both snippets are from layouts/_default/_markup/render-image.html which Hugo will use to override how images are linked in Markdown documents)

Now yes, before you say anything, I’m aware that the use of <center> tag is technically not HTML 5 compliant, but… well, I’ll worry about that for another day.

All you need to know is that a <picture> has a <source>. Within the source is a srcset, which is the actual file to grab, and a type that indicates what it is. In theory, I could have multiple <source> tags, with differing types, sizes, whatever, for the browser to pick from as it chooses. At the end, there has to be a plain <img> tag for browsers that do not support <picture>, who will ignore the rest and only pick up on <img>.

The <img> here has a filter that changes the extension from .webp to .png, meaning if the browser ignores the rest, or refuses to load the WebP one, the default fallback is the PNG formatted file, which loads without issues.

The end result is that your browser will load the much smaller WebP file if it can, and will fall back to the ever-reliable PNG files if it cannot.

And just for comparison, have a directory listing:

$ ls
Size Name
3.4M blur_shot.png
5.2k blur_shot.webp
886k featuredImage.png
 13k featuredImage.webp
4.6k index.md
3.7M lamp_correct_wb.png
124k lamp_correct_wb.webp
3.8M lamp_neutral_wb.png
145k lamp_neutral_wb.webp
188k lenscap.png
 21k lenscap.webp
 48k nikon_manual_wb_list.png
 33k nikon_manual_wb_list.webp
2.4M wb_2500k.png
 28k wb_2500k.webp
1.7M wb_9900k.png
 32k wb_9900k.webp
2.4M wb_auto.png
 29k wb_auto.webp
1.8M wb_cloudy.png
 26k wb_cloudy.webp
2.4M wb_correct.png
 24k wb_correct.webp
2.4M wb_preset.png
 26k wb_preset.webp