WebP and nginx with graceful legacy fallback
This is my very first time when I’m writing a blog post in English.
WebP
The main reason I’m writing this post is my recent experience with WebP format on my Node.js project.
Probably you’ve heard something about this format before and know what it is, but I have to tell a few words anyway. WebP is a modern image format developed by Google and its main feature is a size efficiency in various conditions. Why it is important? Let’s remember all the cases when we should use different image formats.
PNG. A transparent image with alpha channel. It is lossless and PNG files are usually huge. However this format supports 32-bit color (24-bit for RGB and 8-bit for alpha channel), so images can be of high quality.
JPEG. A good old format for photos. But it isn’t so efficient as modern WebP and HEIF. Moreover, it doesn’t support transparent images.
GIF. A 31 years old format for animated images compression. It’s widely supported by browsers. GIF supports only 256 colors. It also supports transparency, but usually, the quality is awful because of 256 colors.
Sounds depressing, isn’t it? Don’t upset, there is a hope when WebP will be supported by all major browsers, we will forget this as a terrible nightmare. Currently, Blink is the only browser engine, which supports WebP image format. However if we will look at relative usage we will see that 73% of global Internet users can see WebP in their browsers. WebP surely worth it.
Convert to WebP
There are thousand ways to convert your existing images to WebP. To do it manually on MacOS you can run following commands:
brew install webp
cwebp -q 90 image.png -o image.webp
But it really depends on your platform and image library. I can’t name all possible options. For my web service, I’m using Node.js and ImageMagick for this.
nginx
On this step, I’ll help you configure a nginx web-server in the easiest way to support WebP.
First of all, you should put your new WebP images near to your old JPEG/PNG/GIF images, they should have the same name but with .webp
extension. Then let’s change a nginx configuration. We need to change http
section, usually, you can find it in the /etc/nginx/nginx.conf
file, add the following config there:
http {
# ...
map $http_accept $webp_ext {
default "";
"~image\/webp" ".webp";
}
map $uri $file_ext {
default "";
"~(\.\w+)$" $1;
}
# ...
}
Also, we should make a location
for our images in a server
section. Usually you can find a server
section in the /etc/nginx/conf.d/default.conf
file, but it can depend from your basic nginx configuration.
server {
# ...
location ~* "^(?<path>.+)\.(png|jpeg|jpg|gif)$" {
try_files $path$webp_ext $path$file_ext =404;
}
# ...
}
And finally please ensure that your /etc/nginx/mime.types
file contains the following line:
image/webp webp;
If not, you should put it there manually. So nginx will know which Content-Type
header it should send for files with .webp
extension.
And that’s all. Now you can point any of your images normally. If it has corresponding WebP version and a current browser supports WebP nginx will return the WebP version. In any other cases, the legacy format version will be used.
How it works
It works really nice, but what’s under the hood? For every request nginx creates two variables $webp_ext
and $file_ext
$webp_ext
equals.webp
if current browser sendsimage/webp
in theAccept
header. Or it equals empty string otherwise.$file_ext
equals file extension (e.g..png
) of current URI if current URI has it. Or it equals empty string otherwise.- In the
location
for images, the$path
without extension is captured from incoming URI. And after that nginx tries to find a WebP version by concatenating$path
and$webp_ext
variables. If the file doesn’t exist nginx will try the next$path
and$file_ext
.
You will see a legacy file extension in the URI whether it’s WebP or not, but browsers are okay with that because nginx sends correct Content-Type
for WebP files.
That’s the secret.
I would be glad if this post helped you with the basic concept of how to make your website WebP ready and keep it compatible with all browsers. In my case, the main page of my website decreased from 1,6 MB to 900 KB. That’s a significant difference. People with bad Internet connection will be happy.
Useful links
- The official WebP website
- JPEG vs WebP and PNG vs WebP comparison.
- Browser support