likes
comments
collection
share

H5、小程序能用 webp 图片吗?如何判断环境是否支持?

作者站长头像
站长
· 阅读数 4

最近我在做 H5、小程序的性能优化,其中一项优化是把 H5、小程序的 jpg、png 图片转换为 webp 图片,这是因为相比 jpg、png,webp 体积更小、传输速度更快。

转换方法很简单,现在各大云服务商基本都提供了方法。比如 腾讯云 只需要在图片 CDN 链接后面拼接一些参数:

不过我还是遇到了些小麻烦,从 can I use 查询发现,目前还有少部分浏览器不支持 webp。所以在 H5、小程序使用 webp 格式图片时,我需要做一些兼容。

H5、小程序能用 webp 图片吗?如何判断环境是否支持?

一番研究后,我知道了判断环境是否支持 webp 的几种办法。对这些办法的优劣,我也有自己的观点,于是我便整理了这篇文章。

拳打 H5,脚踢小程序。我是「小霖家的混江龙」,关注我,带你了解更多实用的 H5、小程序武学。

toDataURL('image/webp')

代码

第一种 H5 的判断方法,其实是判断 H5 能不能利用 canvas 的 toDataURL() API 得到一张 webp 图片。

function isWebpSupported() {
  try {
    return document.createElement('canvas')
      .toDataURL('image/webp')
      .indexOf('data:image/webp') === 0
  } catch (e) {
    return false
  }
}

原理

这种方法原理是啥呢?我们可以继续在 Can I use 查询 toDataURL('image/webp') 的兼容性。

H5、小程序能用 webp 图片吗?如何判断环境是否支持?

可以看到,兼容 toDataURL('image/webp') 的浏览器、是兼容 webp 浏览器的子集。

H5、小程序能用 webp 图片吗?如何判断环境是否支持?

换句话说,这是一种「宁杀错一百,也不放过一个」的方法。举 Safari 浏览器为例子,它其实是可以展示 webp 图片的,但它会被这种 toDataURL('image/webp') 方法误伤。

H5、小程序能用 webp 图片吗?如何判断环境是否支持?

优缺点

这种方法的优缺点如下:

  • 优点:代码短小,且方法是同步的,不影响首屏性能。
  • 缺点:误伤性太高,iOS 的 Safari 浏览器被全部误伤。

微信小程序能用吗

这种判断方法微信小程序可以使用吗?很遗憾不可以。

我们之所以用 toDataURL('image/webp') 判断 H5 能不能使用 webp,前提是我们知道 兼容 toDataURL('image/webp') 的浏览器、是兼容 webp 浏览器的子集

但我在微信官方文档中,没有看到类似 canvas 的 toDataURL('image/webp') 是 webp 子集的描述。基于此,我判断微信小程序不能用这个方法。

加载一张 webp 图片试试,看会不会出错

代码

第二种 H5 的判断方法,是直接异步加载一张 webp 格式的图片。如果加载成功,证明环境能支持 webp;如果加载失败,证明环境不支持 webp。

function isWebpSupported() {
  if (!Image) {
    return Promise.resolve(false)
  }

  return new Promise((resolve) => {
    const img = new Image()
    img.onload = function () {
      resolve((img.width > 0) && (img.height > 0))
    }
    img.onerror = function () {
      resolve(false)
    }
    img.src = 'data:image/webp;base64,UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA';
  })
}

原理

这种方法来源于 Google 官方文档,webp 其实支持四个功能,无损压缩、有损压缩、透明度和动画,每个功能对应了一张 webp 图片:

function checkWebpFeature(feature, callback) {
  const kTestImages = {
    lossy: "UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA",
    lossless: "UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==",
    alpha: "UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==",
    animation: "UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA"
  }
  const img = new Image()
  img.onload = function () {
    const result = (img.width > 0) && (img.height > 0)
    callback(feature, result)
  }
  img.onerror = function () {
    callback(feature, false)
  }
  img.src = "data:image/webp;base64," + kTestImages[feature]
}

如果对四种功能都进行判断的话,代码会变得很臃肿。所以实际开发中,基本只选择一张 webp 的图片。

Can I use 查询结果来看,浏览器要么是先支持 webp 的有损压缩,再支持 webp 的无损压缩、透明度和动画;要么是有损压缩、无损压缩、透明度和动画一起支持。因此,我们往往选择一张支持动画的 webp 图片,用它去试探浏览器是否支持 webp 格式。

优缺点

  • 优点:基本不会误伤;
  • 缺点:异步加载,可能无法及时转换图片链接、影响首屏性能。如果 H5 不选择 CSR,而选择 SSR,则无法使用此方法。

微信小程序能用吗

这种方法小程序可以用吗?理论上可以,但不推荐使用。

微信官方文档上虽然提到了 createImage 方法,但我实际测试发现,这个方法竟然没了 (*  ̄︿ ̄)。

H5、小程序能用 webp 图片吗?如何判断环境是否支持?

我们使用此方法,就必须在 wxml 中手动写一个 image 标签,再给它绑定 onloadonerror 事件。这意味着:

  • 如果我们把这个标签放到自己封装的 WebpImage 组件中,WebpImage 被多次使用后,小程序页面会多出很多额外的节点。
  • 如果我们把这个标签放到页面上(比如 index 页面),就需要给每一个用户可能直接访问的页面都加上这个标签。也会出现很多额外的节点。

因此不推荐使用。

直接判断版本

代码

第三种方法,就是直接判断版本号,Android 版本大于 4.4.4,iOS 大于 14.0.0 时,认为 webp 可用。

H5 通过 ua 获取系统版本号的文章很多,我们这里给出小程序的代码。

function isWebpSuported() {
  try {
    const { system, SDKVersion } = wx.getSystemInfoSync()
    const [sysName, sysVersion] = (system || '').split(' ')
    if (!compareVersion(SDKVersion, '2.9.0')) {
      return false
    }

    if (
      sysName.toUpperCase() === 'ANDROID' &&
      compareVersion(sysVersion, '4.4.4')
    ) {
      return true
    }

    if (
      sysName.toUpperCase() === 'IOS' &&
      compareVersion(sysVersion, '14.0.0')
    ) {
      return true
    }

    return false
  } catch (e) {
    return false
  }
}

原理

我们已经通过 Can I use 知道:

  • Android 4.4.4 以下,iOS 14 以下的浏览器不支持 webp。

又从 微信小程序 image 组件文档 里知道:

  • 基础库版本 > 2.9.0 支持 webp。

那么干脆把所有条件都做一个组合,就得到了上述代码,其中 compareVersion()微信官方文档 中比较版本号的代码。

优缺点

  • 优点:同步判断、不影响首屏性能;误伤范围小;且 CSR 和 SSR 可用。
  • 缺点:无明显缺点。

总结

本文介绍了 H5、小程序使用 webp 格式图片时,判断环境是否支持的方法。

  • 方法一:利用 toDataURL('image/webp') 判断。H5 支持,但是会误伤大部分浏览器;小程序不支持。
  • 方法二:利用一张小体积的 webp 图片试探。H5 CSR 时支持,但因为方法是异步的、可能影响首屏性能;H5 SSR 时不支持;小程序支持,但实现不优雅。
  • 方法三:利用版本号判断。H5 和浏览器均支持,是最佳实现方案。

拳打 H5,脚踢小程序。我是「小霖家的混江龙」,关注我,带你了解更多实用的 H5、小程序武学。

转载自:https://juejin.cn/post/7347161048573558799
评论
请登录