Always look your best: WebP, source sets and Images API

Blog post header for WebP, source sets & Images API
October 31, 2019


Images play an integral part in the user experience. A first impression is made in a split second, so it’s important that the images on your website always look their best. On the other hand, speed is crucial to usability and search engine ranking, so finding the right balance can be a real pain.

WebP — The best of both worlds

The pace that new technologies are introduced into the realm of web development is overwhelming. It seems like there's a new framework, language or application surfacing every other week. However, despite the ubiquity of photos on the web, there's been very little advancement in image formats since the mid-1990s. SVG has been making headway, but vector graphics are poorly suited for photographs and comparable graphical assets.

Having been designed primarily for photographs, JPEG's lossy compression is essentially based on tricking the eye. As a result, JPEG is a poor fit for images with sharp lines and flat color surfaces, resulting in visible artifacts even on relatively high quality settings. PNG is equally ill fit for large 24-bit photographs, as the file size skyrockets due to the lossless compression algorithm.

Originally developed by On2 Technologies and later acquired by Google, the WebP image format is designed to offer the best of both worlds. In comparison to JPEG, WebP's compression algorithm produces better quality with comparable file size, or alternatively, smaller file size with comparable quality. Where WebP shines in particular are the aforementioned sharp lines and flat color surfaces, enabling near-PNG quality even with lossy compression. WebP's feature set also includes lossless compression and alpha channel (partial transparency), but with a smaller file size than PNG.

PNG image shrunk from the same 900x900 PNG at 235.91 KB

WebP image, compressed with 70% quality from the same 900x900 PNG and then converted back to lossless PNG for cross browser compatibility. WebP was 42.43 KB

JPEG image, compressed with 70% quality from the same 900x900 PNG at 47.50 KB

Sounds good, right? Hold on, there’s a catch. Even though WebP was introduced as early as 2010, browser vendors have been slow to adopt it. At the moment, WebP is supported by Chrome and other Chromium-based browsers, but not Firefox and Safari. Usually this would be a deal breaker, but fortunately there’s a simple way to implement WebP with a JPEG fallback using source sets and Contentful's Images API.

Source sets — built-in plan B

HTML source sets are a method of defining multiple versions of the same asset, such as an image. It’s then up to the browser to determine which version of that asset is best suited in terms of compatibility or some predetermined condition, for example viewport size.

In this example, source sets are used to display a Contentful WebP image with a JPEG fallback, but the same principle can be used to define multiple sources for <audio> or <video> tags. Having said that, please note that transcoding audio and video is not possible in the same way that the Images API is able to transcode images on the fly.

Let's say we’ve uploaded an uncompressed 4000 x 3000 TIFF image to Contentful's media bank. Since it’s not practical to display such a gargantuan image on the front-end as-is, we need to scale it down to, say, 800 x 600, and use lossy compression. Thanks to WebP's superior algorithm, we can afford to drop the quality down to 80%. Just in case, we’ll use 90% quality for JPEG to avoid those nasty artefacts.

Next, let's build the URLs for requesting the scaled and compressed images from the Images API.

AttributeURL ParameterWebPJPEG

WebP Image URL<SPACE_ID>/<ASSET_ID>/image.tif?w=800&h=600&fm=webp&q=80

JPEG Fallback Image URL<SPACE_ID>/<ASSET_ID>/image.tif?w=800&h=600&fm=jpg&q=90

Now that we have the URLs for the WebP and JPEG images, the only thing left to do is to place the URLs in the srcset-attributes of the <source> tags. The <img> tag is used both for backwards compatibility and to house additional attributes such as alt.

Pro-Tip™: Use Contentful's asset description field for alt text.

HTML Source Sets

  <source srcset="/path/to/image.webp" />
  <source srcset="path/to/image.jpg" />
  <img src="/path/to/image.jpg" alt="Source sets are awesome!" width=”800" height="600" />

Presto! Crispy WebP image for Chromium browsers, JPEG for all the rest. Need to change the dimensions on the front-end? Just tweak the URL parameters, no need to touch the source image.

Simple, right? But wait, there's more! Source sets and Images API can also be used to display different image dimensions for different devices. For example, let's say we want to optimise performance by displaying an 800 x 600 image for desktop clients and a 400 x 300 image for mobile clients.

Again, we'll use the same principle. Multiple versions of the original TIFF image are requested via the Images API and then presented as alternative sources inside the <picture> tag. This time, we'll also include predetermined conditions by defining viewport width using the media attribute. In addition, instead of setting fixed dimensions for the image, we’ll make it responsive by setting the attribute style="width: auto;” for the img tag.

800 x 600 WebP Image<SPACE_ID>/<ASSET_ID>/image.tif?w=800&h=600&fm=webp&q=80

400 x 300 WebP Image<SPACE_ID>/<ASSET_ID>/image.tif?w=400&h=300&fm=webp&q=80

HTML Source Sets

  <source media="(min-width: 800px)" srcset="/path/to/image_800x600.webp" />
  <source media="(min-width: 400px)" srcset="/path/to/image_400x300.webp" />
  <img src="/path/to/image_400x300.jpg" alt="Source sets are awesome!" style="width: auto;" />

Contentful images API — always on time

With legacy CMSes, it’s still very common to see content creators spending enormous amounts of time cropping and scaling every single image manually. The alternative is even worse, but sadly it's not uncommon to see websites cripple their performance by displaying completely unprocessed images.

While it’s possible to implement an image scaling pipeline to legacy CMSes, it requires installing and configuring additional modules and still being limited to a fixed set of dimensions and compression rates. Should those settings change, a fair amount of time consuming back-and-forth hassle is required between the backend and frontend developers. A far cry from the convenience of the Images API!

Another clever Images API use case is metadata images. Two of the most common implementations are Open Graph (Facebook, LinkedIn etc.) and Twitter Card. Less surprisingly, both implementations have their own recommended image sizes and aspect ratios. Fortunately, this is not a problem thanks to a couple of neat tricks the Images API has up its sleeve.

As with our previous example, the original image has a 4:3 ratio. Facebook recommends 1200 x 630 dimensions for the Open Graph image, making its ratio approximately 2:1. For reasons unknown, we don't want to crop the image, so to avoid stretching it we'll fill the remaining space with a Facebookesque shade of grey.

Twitter summary cards, on the other hand, have a square image with a 1:1 ratio, so there's no way to avoid cropping. By default, the cropped image's focus point is center, but that's a bit risqué if the image has people in it. Therefore we'll tell the Images API to focus on the largest face found in the image. Yes, you read correctly - it's really that good!

AttributeURL parameterOpen GraphTwitter Card
Background colorbgrgb:E9EBEE-

Twitter Card Image URL<SPACE_ID>/<ASSET_ID>/image.tif?w=300&h=300&fm=png&fit=thumb&f=face

Open Graph Image URL<SPACE_ID>/<ASSET_ID>/image.tif?w=1200&h=630&q=90&fit=pad&fm=jpg&bg=rgb:E9EBEE

HTML Header Section

<html lang="en">
    <!-- Twitter Card -->
    <meta name="twitter:card" content="summary" />
    <meta name="twitter:title" content="Images API is Awesome!" />
    <meta name="twitter:description" content="Image transcoding on the fly." />
    <meta name="twitter:image" content="/path/to/twitter_card_image.png" />
    <!-- Open Graph -->
    <meta property="og:site_name" content="My Awesome Contentful Site" />
    <meta property="og:title" content="Images API is Awesome!" />
    <meta property="og:url" content="" />
    <meta property="og:type" content="website" />
    <meta property="og:description" content="Image transcoding on the fly." />
    <meta property="og:locale" content="en_US" />
    <meta property="og:image" content="/path/to/open_graph_image.jpg" />

Wrapping it all up

And there you have it, folks. Quick and simple ways to take advantage of the WebP image format, source sets and a few clever Images API tricks. Be sure to dive into the documentation for further information about all the wonderful features the Images API has to offer. Now there’s no excuse to not have your images always look their best!

About the author

Don't miss the latest

Get updates in your inbox
Discover new insights from the Contentful developer community each month.
add-circle arrow-right remove style-two-pin-marker subtract-circle