How to automatically add WebP post banners to Jekyll for faster load times
Most modern browsers can handle the smaller & speedier WebP versions of images, yet generating them manually can be a pain! Here’s how to do it automatically in Jekyll.
I recently updated my site template to support automatic WebP conversion for the banners of every post. This requires both generating the files, and serving them correctly, with no extra manual effort.
A full Gist of this post is available.
Generating WebP files
There’s a library that can do this all for us, unsurprisingly called jekyll-webp
!
Setting it up is straight-forward:
- Add
jekyll-webp
to yourGemfile
. - Add
jekyll-webp
to your_config.yml
’splugins
section. - Finally, add a
webp
config object into your_config.yml
. Below are the settings I use, a description of each is available on the repo:
webp:
enabled: true
quality: 95
img_dir: ["/assets/images/banners"]
nested: true
regenerate: false # Set to true if settings have been changed
formats: [".jpeg", ".jpg", ".png"]
Once the configuration is set up, run bundle install
then bundle exec jekyll serve
, and any images in /assets/images/banners
will have a WebP version generated!
Displaying webp files
Now the post’s banners are in WebP format, they need to be displayed safely and only to browsers that can support them.
Prep work
First, we need to create a webp.html
somewhere. I used _includes/custom/webp.html
.
Next, we need to include it wherever we want our WebP / other image formats to appear. For me, this is my home.html
& post.html
files, where I want to display the image inside an a
tag:
<a class="post-link" href="{{ post.url | relative_url }}">
{% include custom/webp.html path=post.image alt=post.title %}
</a>
Make sure the path
and alt
parameters map to something useful in your template!
Note: If you don’t already have a post.html
/ home.html
page because you’re using a template’s defaults, GitHub has guidance on how to create them.
Checking WebP file exists
Next, we need to build our webp.html
to show these WebP banners if the user’s browser supports them, and they’ve been successfully generated.
Jekyll templates use the quite limited language Liquid, so we have to do some quite tedious string manipulation to:
- Remove the extension from the file’s path (e.g.
.png
,.jpg
). - Add
.webp
onto the end. - Check this new path actually exists.
This can definitely be done more concisely, but I prioritised ease of reading / maintaining:
{% assign path = include.path %}
{% assign alt = include.alt | default: "article" %}
{% assign image_parts = path | split: '.' %}
{% assign extension_length = image_parts | last | size | plus: 1 %}
{% assign base_path_length = path | size | minus: extension_length %}
{% assign base_path = path | slice: 0, base_path_length %}
{% assign webp_path = base_path | append: '.webp' %}
{% assign webp_exists = site.static_files | where: "path", webp_path | first %}
Displaying WebP files
Finally, we’re going to use Picture and source sets to let the browser determine if it can actually use the WebP we’re providing it. If not, it’ll use our original image instead:
<picture class="bg-img">
{% if webp_exists %}
<source type="image/webp" srcset="{{ webp_path }}" />
{% endif %}
<img src="{{ path }}" alt="Preview image of {{ alt | escape }}" />
</picture>
You’ll notice we’re also using our alt
parameter to set a somewhat useful alternative text for accessibility, although this could of course be made more specific if the banner image is important.
Extra details
CSS
Whilst your template will likely differ, for my site this is the CSS that sets the size & scaling of the image:
.bg-img {
height: 180px;
border-radius: 0.17rem;
display: block;
overflow: hidden;
}
.bg-img img {
width: 100%;
height: 100%;
object-fit: cover;
}
WebP limitations
I found some colours (especially dark orange) just wouldn’t render properly in WebP, regardless of quality settings. I strongly suspect this is an issue with the converter I’m using (since it has other long-standing broken functionality). It’s good enough for now, but may need replacing!
Conclusion
Using WebP drastically reduced the size of my site, and now it’s all automatic I won’t need to “fix” it again in the future. It’s long overdue, and I won’t be retroactively fixing past posts, but at least further posts will receive the benefits!
In terms of next steps, I’d like to add automatic banner image resizing, and be able to provide an alternate image for social media sharing. Neither of these is essential, and is arguably bloat, so perhaps not any time soon.
Everything in this post is available as a Gist.