As I was randomly browsing through some site optimization content, I got this suggestion that I should use a “modern” image format such as “webp” to get lower image sizes and implicitly speed up page loading time. I can’t say it made a lot of sense to me that very moment, thus the rabbit hole I have soon found myself going into.
1. Introduction
To sketch out some context, the well-known imge formats such as “jpeg”, “png” or “gif” are with us for 25 years or more; they were put together in a time when both storage and cpu processing power were premiums rather than commodities. That meant accepting compromises and precise product-market fits: “jpeg” became the universal format for everyday pictures, “png” for icons or computer generated images and “gif” was mostly delegated to short animated sequences once the patent covering the corresponding compression algorithm expired in the early 2000s.
Come the early 2010s and the commodificaton of computing: older ideas about how image compression could be optimized would not only become reality, but new standards were actually pushed forward, all this without many people realising. Also, this was the time when engineers started to consider that hardware support could be leveraged to speed up both encoding and decoding of image or video content on portable devices such as mobile phones. As a consequence, we got what it seemed to be a patchwork of new image and video formats.
Early 2020s saw browsers decide on what formats would be supported and which were to be ignored for time being, while operating systems and image processing software still did their thing with supporting what felt best for their audience. Considering “heic” / “heif” as an example, this is the standard image format with Apple devices, including proprietary hardware support for encoding and decoding. Working with such images in their native format throughout other operating systems or on other devices may sometimes involve purchasing additional plugins or may not even be possible to start with. This means that most applications that display images need to perform transparent conversions from whatever the customer is providing to one of the more widely supported formats.
As of now, only 2 modern image formats seem to have extensive browser support: “webp” and “avif”. They both attempt to replace all previous use cases, that is to provide good results in terms of quality and size for every type of image, from everyday pictures to computer generated drawings, symbols, icons or short animated sequences. The second of the 2 (“avif”) goes a few steps further with HDR (high dynamic range) support.
2. Exploring the new image formats
Context aside, using these formats on websites and web applications is simple enough, with a starting point as simple as having your image processing software save the image in the particular format, instead of the standard “png” or “jpeg”. This goes on the usual way, with uploading pictures and adding “img” tags.
Then again, there is a catch, a few of them actually:
- Support for “exotic” formats tends to be spotty or sub-optimized. Your image processing software may not be able to save “webp” or “avif” images, or if it does, you may not get the best result in terms of quality and size.
- Depending on your audience or use case, you may have a few users or customers with browsers that do not support such formats, or may only know about “webp”. Forgetting about these image formats and sticking to “the old reliables” is always an option if that comes with a better product-market fit for your particular use case.
- If you decide to maximize support, you need to store at least 2 copies of every image, one in the “modern” format of your choice and then another in the older, widely supported format. This will provide a better experience to your users or customers, but with the additional storage cost.
3. Implementation in the web context
In practical terms, supporting the wide audience can be achieved through a few methods:
- The “picture” tag available with HTML5, with a “catch-all” or “fall-through” in the form of an “img” tag pointing to the picture in the widely supported format. This “picture” tag can also be used to designate an image suitable for user screen size, out of a longer list. Unfortunately, this comes with browser compatibility risks: both the “new” and “old” picture could be loaded at the same time by a particular browser variant, turning the optimisation attempt into a regression.
<picture><source srcset="flowers.webp" type="image/webp"><img src="flowers.jpg" alt="Flowers"> </picture>
- A javascript based fallthrough, with specifying an “onerror” handler for the “img” tag loading the picture in the new format. That handler would force loading the image in the older format in a later step. While this may ultimately display the required image, the user experience will most likely be sub-optimal on older browsers.
<img src="flowers.webp" alt="Flowers" onerror="this.onerror=null;this.src='flowers.jpg';">
- A server side redirect based on browser request headers. This will work in almost all situations, as the proper image format will always be returned for display. Also, there is no risk of browser loading multiple image copies. The only risk is that, if the user decides to save the file locally, they may get a misleading file extension for the image.
# Frontend: <img src="flowers.jpg"> # Backend .htaccess file for Apache httpd: RewriteEngine On RewriteCond %{HTTP_ACCEPT} image/webp RewriteRule "^flowers.jpg" "flowers.webp" [L] # Nginx configuration: if ($http_accept ~* "image/webp") { rewrite ^flowers.jpg flowers.webp last; }
- Dynamic image generation can also be adjusted, but you need to both check the “Accept” http header and the server-side availability. This may not automatically result in smaller image sizes, depending on the content that is being generated. This means that additional evaluation and testing must happen before deciding on this particular course of action. Example for PHP with image generation using GD:
$webp_available = ((imagetypes() & IMG_WEBP) > 0) && is_array($_SERVER) && array_key_exists('HTTP_ACCEPT', $_SERVER) && str_contains($_SERVER['HTTP_ACCEPT'], 'image/webp'); header("Content-Type: image/". ($webp_available ? 'webp' : 'png')); header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0"); header("Pragma: no-cache"); if ($webp_available) { ImageWEBP($image, null, 100); } else { ImagePNG($image); }
4. Server side: the heavy lifting
If there is not enough support from client-side image processing software in terms of making best use of new image formats, or if maybe the effort of saving multiple copies of the same picture becomes a chore, the natural option could be to just give up, although there might be help available on the server side. Depending on platform used, there could be options available:
- Content management systems may have plugins to automatically duplicate files and fill in all the blanks. Such plugins are readily available for WordPress, for starters.
- Batch image conversion can be done with a few Linux shell commands, if desired:
-- Install webp and avif cli tools # dnf install libwebp-tools libavif-tools -- Add webp copies for all png images in the current directory $ find . -maxdepth 1 -type f -name "*.png" -exec sh -c 'cwebp -lossless $0 -o ${0/%.png/.webp}' {} \; -- Add avif copies for all jpeg images, recursively $ find . -type f -name "*.j[p|pe]g" -exec sh -c 'avifenc $0 ${0/%.j[p|pe]g/.avif}' {} \;
5. Conclusion
This exploration was eye opening, for me at least. I personally don’t think there is room for more than some random, but not very consequential improvement for the average website when implementing a new image format. There are other use cases, though:
- CDN services (content delivery networks) may do transparent image conversion and then reap benefits through volume savings.
- Presentation websites or social media platforms focused on sharing pictures may use “avif” format for HDR support, displaying better quality images to customers that use compatible screens (e.g. recent Apple devices or high end desktop monitors).