# 检测页面是否支持 webp

日期:2024 年 5 月 31 号

# webp 图片

WebP 格式的图片是由 Google 开发的一种现代图像格式,它旨在为 Web 上的图像提供更优的压缩性能。

  • 高效的压缩:WebP 提供了比 JPEG 更优的有损压缩和无损压缩,这使得 WebP 图片在保持相同视觉质量的同时,文件大小更小。

  • 支持透明度:无损 WebP 支持透明度(Alpha 通道),这对于需要显示半透明效果的图片非常有用。

  • 支持动画:WebP 支持动画,类似于 GIF,但提供了更优的压缩和更丰富的色彩。

  • 支持无损和有损压缩:WebP 支持无损压缩,这意味着压缩后不会损失任何图像质量。同时,它也支持有损压缩,以进一步减小文件大小。

  • 更好的视觉质量:在同等文件大小的情况下,WebP 能够提供比 JPEG 更好的视觉质量。

  • 更快的加载时间:由于 WebP 图片的文件大小通常更小,因此加载速度更快,有助于提高网页的加载性能和用户体验。

  • 节省带宽:更小的文件大小意味着在网络传输时可以节省带宽,对于移动设备和带宽受限的环境尤其有利。

  • 支持多种图像类型:WebP 支持多种图像类型,包括静态图像、透明度图像、动画图像等。

  • 现代浏览器支持:大多数现代浏览器都支持 WebP 格式,这使得 WebP 图片可以在广泛的用户群体中显示。

  • 易于转换:有多种工具和库可以将现有的 JPEG、PNG 和 GIF 图片转换为 WebP 格式,方便开发者使用。

总体来说,webp 和 其他格式的图片比就是:同等大小,质量更高。同等质量,大小更小,而且还可以有损更小。支持的功能多,转换方便,浏览器兼容性好。

# 判断浏览器是否支持 webp

# Image 对象检测

function isWebPSupported() {
  var img = new Image();

  // true if supported
  img.onload = function () {
    var result = img.width > 0 && img.height > 0;
    console.log("WebP support: ", result);
  };

  // false if not supported
  img.onerror = function () {
    console.log("WebP support: ", false);
  };

  img.src =
    "data:image/webp;base64,UklGRjoAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA";
}

isWebPSupported();

# HTML5 Picture 元素检测

浏览器会自动选择支持的图片格式。如果浏览器支持 WebP,它会加载 image.webp;如果不支持,则回退到 fallback.jpg。

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

# CSS 背景图像检测

.webp-background {
  background-image: url("webp图片的url地址");
}

/* Fallback for WebP unsupported browsers */
@supports not (background-image: url("webp图片的url地址")) {
  .webp-background {
    background-image: url("fallback.jpg");
  }
}

上述代码中使用到了 css 的 @supports 规则,它是一种特性查询,允许编写依赖于浏览器对特定 CSS 特性支持的样式。

// 当支持 display:grid 时,使用 gird 布局
@supports (display: grid) {
  .container {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
  }
}

/* 如果浏览器不支持 grid-layout,则应用下面的样式 */
.container {
  display: flex;
  flex-wrap: wrap;
}

# Canvas 检测

function isWebPSupportedWithCanvas() {
  return new Promise((resolve, reject) => {
    try {
      const canvas = document.createElement("canvas");
      const base64Url = canvas.toDataURL("image/webp", 0.5);

      const hasWebp = base64Url.indexOf("data:image/webp") !== -1;

      resolve(hasWebp);
    } catch (error) {
      resolve(false);
    }
  });
}

isWebPSupportedWithCanvas()
  .then(function (isSupported) {
    console.log("WebP support with Canvas: ", isSupported);
  })
  .catch(function (err) {
    console.error(err);
  });

# createImageBitmap 检测

# 感觉用它检测 webp 没有意义。如果使用 img 标签加载 webp 资源,浏览器不支持直接就触发了 onerror 事件了。不需要转成 createImageBitmap 再判断。

function isWebPSupportedWithImageBitmap() {
  return new Promise((resolve, reject) => {
    var img = new Image();
    img.onload = () => {
      createImageBitmap(img)
        .then((bitmap) => {
          resolve(true);
        })
        .catch((err) => {
          resolve(false);
        });
    };
    img.onerror = () => {
      resolve(false);
    };
    img.src =
      "https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8d3114f363b44dc49f6be3604fe3b69a~tplv-k3u1fbpfcp-jj-mark:3024:0:0:0:q75.awebp#?w=524&h=500&s=372124&e=png&b=8a7d72";
  });
}

isWebPSupportedWithImageBitmap().then(function (isSupported) {
  console.log("WebP support with createImageBitmap: ", isSupported);
});

createImageBitmap 方法可以接受不同的图像来源并对他们进行裁剪操作,返回的是一个 promise。

# 使用方式

createImageBitmap(image[, options]).then(function(response) { ... });

createImageBitmap(image, sx, sy, sw, sh[, options]).then(function(response) { ... });

# 参数说明

  • image 一个图像源,可以是一个 <img>, SVG <image>, <video>, <canvas>, HTMLImageElement, SVGImageElement, HTMLVideoElement, HTMLCanvasElement, Blob, ImageData, ImageBitmap, 或 OffscreenCanvas 对象。

  • sx 裁剪点 x 坐标。

  • sy 裁剪点 y 坐标。

  • sw 裁剪宽度,值可为负数。

  • sh 裁剪高度,值可为负数。

  • optionsmdn 文档 (opens new window)

var canvas = document.getElementById("myCanvas"),
  ctx = canvas.getContext("2d"),
  image = new Image();

image.onload = function () {
  Promise.all([
    createImageBitmap(this, 0, 0, 32, 32),
    createImageBitmap(this, 32, 0, 32, 32),
  ]).then(function (sprites) {
    ctx.drawImage(sprites[0], 0, 0);
    ctx.drawImage(sprites[1], 32, 32);
  });
};

image.src =
  "https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8d3114f363b44dc49f6be3604fe3b69a~tplv-k3u1fbpfcp-jj-mark:3024:0:0:0:q75.awebp#?w=524&h=500&s=372124&e=png&b=8a7d72";