Automatically create AVIF versions of your images with Craft CMS
One of the reasons I like Craft CMS are image transforms. With just very little code, you can output an image element with the srcset attribute automatically generated as well as the corresponding image versions generated. What makes it even greater is, that you can automatically generate different formats. Like webp or avif. Here a basic example of the
{% set image = entry.headerImage.one %}
{{ tag('img', {
src: image.url,
width: image.width,
height: image.height,
alt: image.altText,
srcset: image.getSrcset( ['300w', '600w', '900w', '1200w', '1500w', '1800w', '2100w', '2400w', '2700w', '3000w'] ),
sizes: "100vw"
}) }}
First I set a variable with the image, this way, it's easier to just write the variable name for the attribute values (and for reuseability).
Craft has a tag
template function, which comes in handy. It will output an img element with the supplied attributes. The first parameter is the element name followed by an object of attributes.
I don't want to go into detail about responsive images here, there are excellent explanations about it available on the web. The part I want to go into detail about is the image.getSrcset( ['300w', '600w', '900w', '1200w', '1500w', '1800w', '2100w', '2400w', '2700w', '3000w'] )
.
The getSrcset
function not only creates the value for the srcset attribute but also generates those images. In my case, I pass an array with 10 values. So 10 different versions of the images are generated. One version with 300px width, one with 600px width, ...
I chose those width-values based on what I think is useful. You don't want the browser to load an unnecessarily large image, but you also don't want to have too many different sizes. That's the compromise I came up with.
Depending on your server, generating the transforms may take a while. While these tasks are running, you can see entries in the "Queue Manager" (under Utilities). I sometimes experience that tasks get stuck. Sometimes it helps to just restart the stuck tast. Sometimes it's better to remove all tasks and visit the page with the images you want to create the transforms for, again. All the transforms, that have not been created yet, new tasks will be created.
Craft also offers the possibility to predefine named image transforms, I prefer to not use it because I don't like to manually create them.
Generating different image formats
The next step is to not only supply different sizes but also different formats. Like webp and avif. Compared to jpg and png images, webp and avif images are much smaller and therefore help to get a good performance. Since some browsers don't support those "new" formats, I use the picture element to always supply the original format as a fallback.
{% set image = entry.headerImage %}
{% set srcsetSizes = ['300w', '600w', '900w', '1200w', '1500w', '1800w', '2100w', '2400w', '2700w', '3000w'] %}
{% set sizes = "100vw" %}
{% if image.extension|lower != "gif" %} {# transforming animated gifs is not a good idea ... #}
<picture>
{% if craft.app.images.getSupportsAvif() %}
{% set avif = clone(image) %}
{% do avif.setTransform({ format: 'avif', quality: 60 }) %}
{{ tag('source', {
srcset: avif.getSrcset( srcsetSizes ),
sizes: sizes,
type: "image/avif"
}) }}
{% endif %}
{{ tag('img', {
src: image.url,
width: image.width,
height: image.height,
alt: image.alt,
srcset: image.getSrcset( srcsetSizes ),
sizes: sizes,
loading: "lazy"
}) }}
</picture>
{% else %}
{{ tag('img', {
src: image.url,
width: image.width,
height: image.height,
alt: image.alt,
loading: "lazy"
}) }}
{% endif %}
Since I use the values for sizes
and the array with the srcsetSizes
more than once, I put them in a variable. (Actually I put the whole snippet in a separate template and include it whenever I use an image…)
When I did my first experiments with avif I found out that the generated images were larger than the webp versions I used to use. That shouldn't be the case. I figured out that I needed to adapt the quality
settings for the transform. The default setting is 82, this can be changed via the general settings though. I was happy with the quality and filesize of the transform of the original image, so I just wanted to lower the value for the avif images. You need to try out what value for the quality attribute works for you. You want the image quality to be just good enough to get the most performance benefit.
PS: there is much more you can do with image transforms in Craft CMS. Cropping the images for example. When doing this, you can also take advantage of focal points.