Skip to content

WebP 图片的优雅降级方案

方案一:<picture> + <source>

HTML <picture> 元素通过包含零或多个 <source> 元素和一个 <img> 元素来为不同的显示/设备场景提供图像版本。浏览器会选择最匹配的子 <source> 元素,如果没有匹配的,就选择 <img> 元素的 src 属性中的 URL。然后,所选图像呈现在<img>元素占据的空间中。

html
<picture>
  <source srcset="demo.webp" type="image/webp"/>
  <img src="demo.jpg" alt="" />
</picture>

方案二:检测支持 + 样式覆盖

如果需要替换背景图片,则可以先检测浏览器是否支持 WebP,不支持的话就在根节点上添加名为 webp-not-supported 的 class,之后通过这个 class 在不支持的浏览器中用兜底图片覆盖。

首先,通过 canvas 的 toDataURL 方法进行检测:

js
const isSupportWebp = function () {
  try {
    return document.createElement('canvas').toDataURL('image/webp', 0.5).indexOf('data:image/webp') === 0;
  } catch(err) {
    return false;
  }
}

判断检测结果,如果不支持则在根节点上添加名为 webp-not-supported 的 class:

js
if (!isSupportWebp) {
    document.documentElement.classList.add('webp-not-supported')
}

最后,通过 webp-not-supported class 控制加载兜底图片。这里以使用了 Sass 预编译器的代码为例子,进一步简化代码:

scss
@mixin webpBg($url) {
    background-image: url($url + '.webp')
    @at-root .webp-not-supported & {
        background-image: url($url + '.png')
    }
}
html
<html class="webp-not-supported">
    <!-- 其他元素略 -->
    <div class="test-pic"></div>
</html>
scss
.test-pic {
    @include webpBg('./image/test')
}