Responsive images: Smaller page sizes with the picture element and WebP

At a recent Bristol Web Performance meetup Bruce Lawson gave a talk on responsive image techniques using the <picture> element he devised and had added to the HTML spec with help from some other clever people. I happened to be starting work on a project that's particularly image-heavy for a client, so it seemed like a great opportunity to try out Bruce's techniques and see what kind of bandwidth savings I could get.

The purpose and syntax of the <picture> element has been covered in a lot of detail elsewhere, so I'll focus on my actual results here. Bruce talked about two ways to use the <picture> element to reduce page sizes and save bandwidth:

  1. Serving smaller image assets to devices with small screens, like smartphones, and
  2. Replacing JPG and PNG images with Google's WebP format for browsers that support it

It's worth noting the <picture> element is a progressive enhancement, so you can happily use it safe in the knowledge that Internet Explorer users will still see regular old <img> elements. Browsers that don't understand the <picture> element, or indeed the WebP image format when delivered via <picture>, will still render a functional page with no missing images.

The other thing to note is that WebP images are, on average, around 30% smaller in filesize than JPG and PNG images of the same quality and physical dimensions. So what did I apply these techniques to?

The Project

To put the results in context, the page being built is a homepage of sorts featuring 9 or 10 separate graphics, all PNG with transparencies, animated with CSS3 keyframe animations. That's a pretty heavy page, and a perfect candidate for testing <picture> and WebP!

Optimisations with <picture>

The original page weighs in at a hefty 779 KB. Here's how each image is served using a plain old <img> element, with no consideration given to data usage:

<img src="images/img_original/raspberry.png" alt="An illustration of some raspberries">

Serving a page stuffed with these to smartphones would be borderline criminal, so I used the <picture> element as described in scenario 1 above to only serve full size PNG images to "large" devices with a minimum browser window width of 750px. 750px is an entirely arbitrary value chosen to try and broadly account for smartphones of varying sizes.

Using <picture> to serve smaller PNG images to smartphones, the page size went down to 380 KB. That's a saving of almost 51%, and easily achieved with just a small amendment to our <img> code:

    <source srcset="images/img_original/raspberry.png" media="(min-width: 750px)">
    <img src="images/img_original/raspberry_small.png" alt="An illustration of some raspberries">

We've halved the page size for smartphones by doing no more than wrapping <img> elements in <picture>, and providing smaller images for browser windows narrower than 750px to fall back to.

Further savings with WebP, and combining techniques

That 51% saving is huge, but we can squeeze a little more out of this page. In scenario 2, we offer browsers that support the WebP image format an alternative to PNG. Unfortunately WebP isn't as well supported as the <picture> element we'll use to serve it, but that's okay. Because <picture> is a progressive enhancement, we can use it to fall back to PNG for any browser that can't take advantage of the smaller filesizes of WebP:

    <source srcset="images/img_webp/raspberry.webp" type="image/webp">
    <img src="images/img_original/raspberry.png" alt="An illustration of some raspberries">

With this approach, our 779 KB original page weight is reduced to 480 KB; a big saving achieved simply by offering WebP images instead of PNGs to browsers that can render them. But for maximum savings, we really ought to combine both scenarios and offer large and small WebP images to supporting browsers depending on screen size, while falling back to large and small PNG images for any that don't. Here is our final code block that gives us the best of both worlds:

    <source srcset="images/img_webp/raspberry.webp" media="(min-width: 750px)" type="image/webp">
    <source srcset="images/img_original/raspberry.png" media="(min-width: 750px)">
    <source srcset="images/img_webp/raspberry_small.webp" type="image/webp">
    <img src="images/img_original/raspberry_small.png" alt="An illustration of some raspberries">

By combining both techniques, our original page weight of 779 KB has been reduced to 480 KB for WebP-loving browsers, and for smartphones that can render the format the page weight has come down from 380 KB to just 234 KB. When compared to our original completely unoptimised page, a WebP-supporting smartphone is now downloading a whopping 70% less data to render the page.

Summary and thoughts

Those page size numbers again:

  • Serving PNG: 779 KB
  • Serving small PNG to smartphones: 380 KB
  • Serving WebP: 480 KB
  • Serving small WebP to smartphones: 234 KB
  • Total saving from unoptimised <img> to responsive WebP: 70%

There are a couple of points to keep in mind at the end of our responsive image page optimisation adventure. Firstly, we're assuming a starting point of a completely unoptimised page. That of course isn't necessarily the case with whatever you're working on at the moment. Perhaps you've developed your own little hacks to deliver responsive images to smaller devices without just serving giant images and not worrying about download sizes, or you're using some sort of javascript solution to gather information about the browser and try to have it download more suitable assets on page load. Hopefully though, now that <picture> has matured and gained decent browser support having been adopted in to the HTML spec, such hacks and workarounds will no longer be necessary.

Secondly, this is clearly an extreme example of the kinds of page weight savings you can get using <picture> and WebP. The design of the page in question has a huge effect on the savings you'll be able to make. This one uses multiple very large PNG images, and where more typical web pages might include fewer images, or images that are generally smaller, the savings to be achieved will scale down accordingly. That said, you'll still see savings worth having even with just one or two small JPGs on the page.

Many thanks to Bruce Lawson for the talk that got me experimenting with <picture> and WebP, and for the nudge to blog about my findings!