Safari is late at the webp party, whilst Firefox and chromium-based browsers heading to the avif party. This means I need to extend my webp feature detection script to look for avif support too.

In january 2019 I forked this script as starting point webp-support from Vitalii Bobrov. I changed the script flow to let this script run as soon as possible in the <head> and to store detection results in sessionStorage so the "heavy lifting" is only done once every visit.

usage of avif and webp in your markup

To use avif and webp images in your markup you can use the `<picture>` element by adding a `<source>` line for each webp and avif:

<picture>
    <source type="image/avif" srcset="image@1x.avif 1x, image@2x.avif 2x">
    <source type="image/webp" srcset="image@1x.webp 1x, image@2x.webp 2x">
    <source type="image/jpeg" srcset="image@1x.jpg 1x, image@2x.jpg 2x">
    <img src="image@1x.jpg" alt="describe image content">
</picture>

This setup suits all visitors, some may see the image@1.jpg (IE11), some may see image@2x.jpg (Edge before Chomium, iOS < 14), some see image@2x.webp (iOS >= 14, Firefox, Edge Chromium) and Chrome users will see the image@2x.avif (as of 01.09.2020). From a progressive enhancement point of view, we will use this snippet above for a while now.

Make sure to put the avif image as first source tag, the browser will display the first media-type he can handle. Have a look at the demo page in the github repository to see the effect.

css background-image usage of avif and webp

In the markup the media-type hint helps us and the browser to deliver the best experience to the user. For css we need a javascript feature detection to help us. I updated my webp detection script to support avif too, and it adds now `.webp` and/or `.avif` to the html element of your page.

setup avif-webp script

For best user experience add the contents of the avif-webp.min.js as an inline script in your `<head>` above any css content, to avoid visible image switches when the avif/webp class is added to your DOM:

<!doctype html>
<html lang="en">
    <head>
        …
        <script><!-- contents of avif-webp.min.js --></script>
        <!-- css comes here -->
        …
    </head>
    <body>
        …

The script stores the feature detection results in the sessionStorage object, to only check browser support on the first impression of the users browsing session. If the user returns to your site and has updated his browser in the meantime, the script will automatically check his browser capabilities again and his user experience may become upgraded if his browser can display now webp or avif images.

css usage

The feature detection script adds `webp` and or `avif` css class(es) to your `<html>` element.

.my-class {
  background-image: url('image.jpg');
}
.webp .my-class {
  background-image: url('image.webp');
}
.avif .my-class {
  background-image: url('image.avif');
}
/* retina support */
@media
    screen and (-webkit-min-device-pixel-ratio: 2),
    screen and (min-resolution: 192dpi),
    screen and (min-resolution: 2dppx) {
    .my-class {
      background-image: url('image@2x.jpg');
    }
    .webp .my-class {
      background-image: url('image@2x.webp');
    }
    .avif .my-class {
      background-image: url('image@2x.avif');
    }
}

Remember that in CSS always the last rule wins. That's why .avif comes always last, so if a browser can display webp and avif, the last rule - in this case avif - will win.

scss bg-mixin

Here is an updated version of the bg-mixin from the original webp detection blog post:

@mixin bg-url($url, $url2x: false, $webp1x: false, $webp2x: false, $avif1x: false, $avif2x: false) {
  background-image: url($url);
  @if $webp1x {
    .webp & {
      background-image: url($webp1x);
    }
  }
  @if $avif1x {
    .avif & {
      background-image: url($avif1x);
    }
  }
  @if $url2x {
    @media
    screen and (-webkit-min-device-pixel-ratio: 2),
    screen and (min-resolution: 192dpi),
    screen and (min-resolution: 2dppx) {
      background-image: url($url2x);
      @if $webp2x {
        .webp & {
          background-image: url($webp2x);
        }
      }
      @if $avif2x {
        .avif & {
          background-image: url($avif2x);
        }
      }
    }
  }
}

generating avif and webp images

As I wrote in the last post, I still use Squoosh to create jpg,png,webp,avif files, to get the best results in every format. Very small images (<=32x32) are better delivered with webp instead of avif.

For my feature detection script I use a 2x2 pixel image and the webp image is 68 Bytes big, the avif image is 431 Bytes big. This is a rare case, but if you have a lot of small icons I would recommend to deliver png and webp or svg to the user and skip avif.

Article Image by Raychan via unsplash and ghost