*.avif *.webp images css background usage progressive enhanced with image-set

*.avif *.webp images css background usage progressive enhanced with image-set

Part 3 of my new image formats as background-image journey (part 1, part 2).

Avif and webp images bring a positive impact on every webpage's payload performance. Today (March 16 2021) avif works only in chromium based browsers and webp have "partial support" in macOS safari, we cannot use one-for-all.

All of the techniques in this post are exampled here: https://avif-webp.raoulkramer.de/.

avif and webp for content images

For content images we use the <picture> element to cover all browsers:

<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" loading="lazy">
</picture>

avif and webp as css background-image

For background-images we needed a feature detection script and special css to use avif, webp png or jpeg as background-image (s). In a month we can get rid of the javascript feature detection and use background-image: image-set(...) instead. The name of it makes no secret what it does: it defines a set of images for a css rule:

.hero {
  background-image: url('fallback-image.png');
  background-image: image-set(
    url('image.avif') 1x,
    url('image@2x.avif') 2x,
    url('image.webp') 1x,
    url('image@2x.webp') 2x,
    url('fallback-image.png') 1x,
    url('fallback-image@2x.png') 2x
  );
}

image-set is yet (march 16 2021) a draft for CSS4 and browser implementation may differ from the draft specification, you need -webkit- prefix for chrome and edge chromiun, the type definition makes chrome ignore the whole definition, but with version 88 firefox will support image-set .

Let's jump to late april 2021, when firefox 88 joins the image-set party and think of a CSS snippet for a js free progressive enhanced *.avif *.webp background-image usage:

.example-class {
  /* fallback image for non image-set supporting browsers */
  background-image: url('image.png');
  /* type function commented out, it makes chromium ignore the image-set */
  background-image: image-set(
    url('image.avif') 1x /* type('image/avif') */,
    url('image@2x.avif') 2x /* type('image/avif') */,
    url('image.webp') 1x /* type('image/webp') */,
    url('image@2x.webp') 2x /* type('image/webp') */,
    url('image.png') 1x /* type('image/png') */,
    url('image@2x.png') 2x /* type('image/png') */,
  );
}

Check out the demo page to see this code in action. At time of writing usage of image-set will decrease page performance on browsers which support avif or webp images but not the image-set definition, because these browsers will only show the fallback image and will not recognise a 2x or higher image resolution. When you switch today your firefox visitors have a decreased performance for a month. Also make sure your build-tools add the -webkit- prefix.

I updated the avif-web.js script, to print a console.info() pointing developers to the image-set usage.

SCSS image-set mixin

The image-set syntax is a bit tricky - my old avif/webp bg mixin expected every image as a parameter and build the css if-by-if line-by-line. So I came up with this:

@mixin bg-image-set($fallback, $imageSet...) {
  background-image: url($fallback);
  @if $imageSet {
    background-image: -webkit-image-set(#{$imageSet});
    background-image: image-set(#{$imageSet});
  }
}

And a usage example:

.example-class {
  @include bg-image-set(
    'assets/hero.jpg',
    url("assets/hero.avif") 1x,
    url("assets/hero.webp") 1x,
    url("assets/hero.jpg") 1x
  );
}

/* css result */
.example-class {
  background-image: url("assets/hero.jpg");
  background-image: -webkit-image-set(url("assets/hero.avif") 1x, url("assets/hero.webp") 1x, url("assets/hero.jpg") 1x);
  background-image: image-set(url("assets/hero.avif") 1x, url("assets/hero.webp") 1x, url("assets/hero.jpg") 1x);
}

First parameter should be a jpg/png image to suit all browser, every other parameter adds a line to the image-set definition.
Always give your image-set definition in this order: avif, webp, png/jpg. The browser will than try every definition and will work with the first image he is capable to show, like source definitions in the picture element.

sum up

To use avif, webp, png/jpg images as a background-image we should use the image-set definition, instead of a custom js feature detection (s)css solution.

Article Image by Guillaume TECHER via unsplash and ghost