How to detect if webp images are supported via CSS
Asked Answered
L

7

18

How do you detect in CSS if webp images are supported?

.home-banner-background {
     background-image: url('img/banner.jpg');
 }
 /*Here is an if statement that will check if webp is supported*/ {
        .home-banner-background {
            background-image: url('img/banner.webp');
        }
}

Is there an "if" statement which can do that?

Levite answered 5/8, 2019 at 13:5 Comment(5)
Pretty sure that is impossible to “detect” using CSS alone.Bud
There are no if statments in css. If something is not supported it simply ignores that rule. A missing image or not supported image will not be ignored since the css is valid.Odle
Only "if statements in CSS" can test property support only -- @supports (property: value){/*rules*/} -- not image file format support. It would be nice to be able to do @supports (background-image: url('existing-image.webp')){/*...*/} but for quite obvious reasons this doesn't work.Helicopter
Here working solution example https://mcmap.net/q/669261/-how-to-use-webp-images-and-support-safariRevelationist
Re: "There are no if statments in css." Both @media and @supports represent if structures.Periodic
H
10

You can use Modernizr. It is a tool that detect available features on the user's browser. It is just a script to add in your website, and with it, you can write something like that :

.no-webp .home-banner-background {
     background-image: url('img/banner.jpg');
 }

.webp .home-banner-background {
     background-image: url('img/banner.webp');
}
Hartnett answered 5/8, 2019 at 13:17 Comment(1)
For clarification, the answer to the question is "CSS cannot currently directly check if the browser supports webp." This solution uses JavaScript with CSS.Undulant
W
17

The modern webkit browser will use the WebP background image with this CSS:

.map {background-image: url('../img/map.jpg');}
  @supports (background-image: -webkit-image-set(url('../img/map.webp') 1x)) {
    .map {background-image: -webkit-image-set(url('../img/map.webp') 1x) }
  }
Wangle answered 29/1, 2020 at 15:10 Comment(1)
Didn't work for me. Safari 13.1.3 seems to support -webkit-image-set but does not support webp and thus it still tries to load it, but can't.Arboriculture
A
14

Use the type() function together with image-set() to provide alternative image formats with CSS. In the example the type() function is used to serve the image in WEBP and JPEG formats. If the browser supports webp, it will choose that version. Otherwise it will use the jpeg version.

.box {
  background-image: image-set(
    url("large-balloons.webp") type("image/webp"),
    url("large-balloons.jpg") type("image/jpeg"));
}

Doku

Ability answered 2/6, 2021 at 13:37 Comment(4)
This solution has very poor browser support at the moment.Heliozoan
Thanks for adding this answer! It can be helpful for people who only need to target specific browsers. I will bookmark and keep an eye on the browser compatibility over the next year - it looks promising... caniuse.com/mdn-css_properties_background-image_image-setLicht
Don't forget the fallback: developer.mozilla.org/en-US/docs/Web/CSS/image/…Hecht
This could be the right answer but it lacks -webkit-image-set and fallback for old browsers. Please, read nice article at MDM: developer.mozilla.org/en-US/docs/Web/CSS/image/…Caerphilly
H
10

You can use Modernizr. It is a tool that detect available features on the user's browser. It is just a script to add in your website, and with it, you can write something like that :

.no-webp .home-banner-background {
     background-image: url('img/banner.jpg');
 }

.webp .home-banner-background {
     background-image: url('img/banner.webp');
}
Hartnett answered 5/8, 2019 at 13:17 Comment(1)
For clarification, the answer to the question is "CSS cannot currently directly check if the browser supports webp." This solution uses JavaScript with CSS.Undulant
P
5

This is currently not supported with CSS.

In the CSS Images Module Level 4 Draft, a fallback solution is suggested, but this is currently not supported anywhere. (2.4. Image Fallbacks and Annotations: the image() notation)

But if it will become part of a standard in some years, you then might be able to write:

.home-banner-background {
    image:image('img/banner.webp', 'img/banner.jpg')
}

Until then you need to use tools like Modernizer, as suggested in the answer of Fifi

Alternatively, the picture HTML tag might something you could think of, but if that is usable in your case depends on how the image should resize on your site:

<picture>
  <source srcset="img/banner.webp" type="image/webp">
  <source srcset="img/banner.jpg" type="image/jpeg"> 
  <img src="img/banner.jpg">
</picture>


Priorate answered 5/8, 2019 at 13:35 Comment(1)
The irony is that when browsers support image notation, they'll almost certainly support webp too.Kidskin
S
2

You could actually just add it to the original declaration without needing multiple classes, @supports, or bringing in another library similar to this:

.home-banner-background {
    background-image: url('img/banner.jpg');
    background-image: -webkit-image-set(url('img/banner.webp') 1x,
                                        url('img/banner-2x.webp') 2x),
                                        /* etc */;
}

Webkit will use the webp images and all others will fallback to the regular image.

Staffordshire answered 19/2, 2020 at 21:29 Comment(4)
Safari also supports -webkit-image-set but not webp. This will fail on iOSWailful
Ah, good call. In some situations recently, I've been checking for user agent, and using the appropriate image format based on that. Can't wait till there's a better way.Staffordshire
Checking the "Accept" header for "image/webp" is much better than guessing based on the user agentArchibold
Pretty sure that both images will be downloaded then and then it totally defeats the purpose of decreasing the size with webp...Lincolnlincolnshire
S
0

This solution works well:

.home-banner-background {
  background-image: url('img/banner.jpg');
}

@supports (gap: 1px) {
  .home-banner-background {
    background-image: url('img/banner.webp');
  }
}

Targeting just browsers which support the gap property ensures a very similar browser support to WebP images. REF: https://caniuse.com/flexbox-gap

Synchronic answered 6/10, 2022 at 7:3 Comment(0)
M
-1

For now (Q1 2023) using image-set is not a sufficient solution because lots of devices that actually support WebP won't get be able to use it. There is a large difference in support coverage of both feature.

I'd opt for Modernizr but it is not tree-shakeable. Code below might be useful to set a class on <body> or use directly in the image wrapper or directive.

// inspired by Modernizr implementation
function supportsWebP() {
  return new Promise((resolve) => {
    const image = new Image();
    image.onerror = () => resolve(false);
    image.onload = event => resolve(event.type === 'load' && image.width === 1);
    image.src = 'data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEAAwA0JaQAA3AA/vuUAAA=';
  });
}
// example usage
const useWebP = await supportsWebP();
const backgroundImage = `/img/picture.${ useWebP ? 'webp' : 'png' }`;
Maun answered 30/3, 2023 at 8:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.