图片资源,在我们的业务中可谓是占据了非常大头的一环,尤其是其对带宽的消耗是十分巨大的。
图片类型的选取及 Picture 标签的使用
首先,从图片的类型上而言,除了常见的 PNG-8/PNG-24,JPEG,GIF 之外,我们更多的关注另外几个较新的图片格式:
- WebP
- JPEG XL
- AVIF
图片类型 | Alpha 通道 | 动画 | 编解码性能 | 压缩算法 | 颜色支持 | 内存占用 | 兼容性 |
---|---|---|---|---|---|---|---|
GIF | 支持 | 支持 | 较高 | 无损压缩 | 索引色(256 | 基本一致 | ALL |
PNG-8/PNG-24 | 支持 | 不支持 | 较高 | 无损压缩 | 索引色(256\直接色 | 基本一致 | ALL |
JPEG | 不支持 | 不支持 | 较高 | 有损压缩 | 直接色 | 基本一致 | ALL |
WebP | 支持 | 支持 | 编解码性能差(低配设备更为显著) | 有损压缩\无损压缩 | 直接色 | 基本一致 | 高版本 Chrome\Opera\Android |
JPEG XL | 支持 | 支持 | 渐进式解码 | 有损压缩\无损压缩 | 直接色 | 基本一致 | 部分高版本 Chrome\Opera\Firefox\Edge |
AVIF | 支持 | 支持 | 编解码性能一般 | 有损压缩\无损压缩 | 直接色 | 基本一致 | 高版本 Chrome\Opera\Android\Edge |
首先,了解了解上述的一些参数含义:
- Alpha 通道:图片是否支持透明的特性
- 动画:很好理解,图片是否支持多帧率动态图片,类似于 GIF
- 编解码性能:图像的解码与编码。这个很关键,很多人对待图片容易忽视图片的编解码性能,解码图像主要从图像文件中读出图像数据,而编码则是将图像数据写入图像文件。解码与编码的过程正好相反。而这两者的性能耗时会影响我们页面的的展示性能。
- 压缩算法:该图片格式是否支持压缩,支持的话,图片的压缩又会分为无损压缩与有损压缩
有损压缩算法是一种数据压缩方法,经过此方法压缩、解压的数据会与原始数据不同但是非常接近。原理是借由将次要的信息数据舍弃,牺牲一些质量来减少数据量、提高压缩比
无损压缩指数据经过压缩后,信息不受损失,还能完全恢复到压缩前的原样。无损压缩通常用于严格要求“经过压缩、解压缩的数据必须与原始数据一致”的场合。
- 颜色支持:会分为索引色与直接色,在过去,为了节省存储空间,并非所有图片都能支持所有颜色值,因此存在索引色这种优化方式。
索引颜色是一种以有限的方式管理数字图像颜色的技术,以节省计算机内存和文件存储,同时加速显示刷新和文件传输。即用一个数字来代表(索引)一种颜色,在存储图片的时候,存储一个数字的组合,同时存储数字到图片颜色的映射。这种方式只能存储有限种颜色。索引色常见有1位(即黑白),8位(即灰阶/256色),16位(即高彩),24位(即真彩),30/36/48位(即全彩)。
直接色使用四个数字来代表一种颜色,这四个数字分别代表这个颜色中红色、绿色、蓝色以及透明度(即 RGBA)。现在流行的显示设备可以在这四个维度分别支持256种变化,所以直接色可以表示2的32次方种颜色。
- 内存占用:图片对内存资源的占用
- 兼容性:影响图片格式能否大规模推广的核心要素之一
WebP vs JPEG XL vs AVIF: JPEG 替代之战
WebP、JPEG XL、AVIF。
WebP
WebP 最初由 Google 在 2010 年 9 月发布,其特性总结如下:
- 可以同时提供无损/有损压缩(像 JPEG 一样)和支持透明度(像 PNG 一样)的图片文件格式
- 支持动画效果(像 GIF 一样)
- WebP 主要优势在于有损编码,其无损编码的性能和压缩比表现一般
- WebP 的缺点在于其编解码性能不是特别理想
- 在兼容性方面,除了 IE,基本已经得到了全系列浏览器支持
下图是我之前还在 TX 的时候做的一个测试对比:
- 目前 WebP 与 JPEG 相比较,据资料考证,编码速度慢 10 倍,解码速度慢 1.5 倍
- WebP 虽然会增加额外的解码时间,但由于大幅减少了文件体积,缩短了加载的时间,大页面图片量较多的场景下,页面的渲染速度是有较大加快的
- 目前而言,是 WebP、JPEG XL、AVIF 三者中兼容性最好的
截止至(2023-02-05)的兼容性图:
JPEG XL
.jxl,JXL 核心比特流于 2021 年 1 月冻结,文件格式于 2021 年 4 月定稿。:
其主要特点有:
- 与传统图像格式(例如JPEG、GIF和PNG)相比,有着更佳的效率与更丰富的功能
- 全面支持广色域和 HDR,支持 Alpha 通道,支持多帧(也就是动画支持)
- 有损压缩时:相同的视觉质量,比 JPEG 小约 60%。
- 无损压缩时:比 PNG 减小约 35%(对于 HDR,减小 50%)。
- 支持无损 JPEG 转码,减小约 20% 文件大小。
- 渐进式解码,专为支持不同显示分辨率的响应式加载
- 开源免费:具有使用三条款版BSD许可证的开源参考实现的免版税格式
JPEG XL 是目前而言,最有可能全面替代传统图片格式(Gif、PNG、JPEG)的下一代标准,当然,在今天,需要看看其兼容性:
.jxl 格式的图片,需要通过 --enable-features=JXL
配置开启,遗憾的是,从 Chrome 110 开始,Chrome 又不再支持 JPEG XL 。
AVIF
最后,我们再来看看 AVIF 格式图片。
- 同样的,与传统图像格式(例如JPEG、GIF和PNG)相比,有着更佳的效率与更丰富的功能
- 支持 Alpha 通道,支持动态图像和动画
- 支持有损、无损压缩。AVIF 文件在低保真有损图像压缩方面表现出色(比 JPEG XL 更优)。压缩的 AVIF 图像保留了很高的图片质量,避免了恼人的压缩伪影等问题
- 相对而言,AVIF 的解码和编码速度不如 JPEG XL,它不支持渐进式渲染
- 最后,再看看兼容性,目前(2023-02-05)它的兼容性介于 WebP 与 JPEG XL 之间
看看 CaniUse 的数据:
从图中可以看到,对于解码性能的对比,结果居然是 WebP > AVIF > JPEG XL 。JPEG XL 的编解码性能并没有其描述的那么强大。
图片格式总结
虽然 AVIF、JPEG XL 等新型图片格式未得到任何浏览器的完全支持,但是在新版本的 Chrome、Firefox 和 Edge Chromium,可以使用配置标志启用对应图像格式,配合 HTML 的 Picture
标签,我们还是可以一定程度上对我们的图片进行格式选择上的优化的。
Picture 元素的使用
HTML5 规范新增了 Picture Element。那么 <picture>
元素的作用是什么呢?
<picture> 元素通过包含零或多个 <source>
元素和一个 <img>
元素来为不同的显示/设备场景提供图像版本。浏览器会选择最匹配的子 <source>
元素,如果没有匹配的,就选择 <img>
元素的 src 属性中的 URL。然后,所选图像呈现在 <img>
元素占据的空间中。
<picture> 元素呢?
<picture>,只有 <img>
元素,我们想尽可能在支持一些现代图片格式的浏览器上使用类似于上述我们提到的 WebP、AVIF 和 JPEG XL 等图片格式,而不支持的浏览器回退使用常规的 JPEG、PNG 等。没错,就是一种渐进增强的思想,该怎么办呢?
<img> 的 src。
<picture> 后,浏览器将原生支持上述的一些列操作,我们来看看对应的语法:
<picture>
<!-- 可能是一些对兼容性有要求的,但是性能表现更好的现代图片格式-->
<source src="image.avif" type="image/avif">
<source src="image.jxl" type="image/jxl">
<source src="image.webp" type="image/webp">
<!-- 最终的兜底方案-->
<img src="image.jpg" type="image/jpeg">
</picture>
上述代码的含义是:
- 第 1 个
- 第 2个
source
元素指向新 JPEG XL 格式的图像。如果浏览器支持 JPEG XL 图像,那么它会选择该图像文件。否则,它将移动到下一个source
元素。 - 第 3 个
source
元素指向一张WebP 格式的图像。如果浏览器能够渲染 WebP 图像,它将使用该图像文件。 - 否则浏览器将回退到使用
img
元素 src 属性中的图像文件。img 元素指向的是 JPEG 格式的图片,它是最终的兜底方案。
source
元素指向新 AVIF 格式的图像。如果浏览器支持 AVIF 图像,那么它会选择该图像文件。否则,它将移动到下一个 source
元素。
简而言之,<picture>
元素的作用:
- 通过
- 通过
<img>
给出兜底的高兼容性图片格式选项 - 浏览器通过对给出的图片格式做特性检测,要决定加载哪个 URL,user agent 检查每个
<source>
的 srcset、media 和 type 属性,来选择最匹配页面当前布局、显示设备特征等的兼容图像。 - 最终,所选图像呈现在
<img>
元素占据的空间中
<source>
给出一系列对兼容性有所要求的现代图片格式选项
模块总结
- PNG-8/PNG-24
- JPEG
- GIF
- WebP
- JPEG XL
- AVIF
其后,着重介绍了 3 种现代图片格式:WebP、JPEG XL、AVIF。相对于 JPEG 等传统格式,它们在色彩表现、动画支持、是否支持无损有损压缩、压损比率、编解码性能上有着更进一步的提升,正在成为下一阶段 Web 图像的标准。
<picture> 元素,借助它,我们能更好的实现图片的渐进增强。
适配不同的屏幕尺寸及 DPR
这里首先会涉及一个预备知识,屏幕的 DPR 值,那么,什么是 DPR 呢?要了解 DPR,又需要知道什么是设备独立像素 以及 物理像素。
设备独立像素
375 * 667 表示的是什么呢,表示的是设备独立像素(DIP),也可以理解为 CSS 像素,也称为逻辑像素:
设备独立像素 = CSS 像素 = 逻辑像素
刚好可以充满整个屏幕。
物理像素
1334 x 750,这里描述的就是屏幕实际的物理像素。
1334 x 750 表示手机分别在垂直和水平上所具有的像素点数。通过控制每个像素点的颜色,就可以使屏幕显示出不同的图像,屏幕从工厂出来那天起,它上面的物理像素点就固定不变了,单位为pt。
设备像素 = 物理像素
DPR(Device Pixel Ratio) 设备像素比
设备像素比描述的是未缩放状态下,物理像素和设备独立像素的初始比例关系。
DPR = 物理像素 / 设备独立像素
iPhone7’s DPR = iPhone7’s 物理像素宽度 / iPhone7's 设备独立像素宽度 = 2
或者是 1334 / 667 = 2
视网膜(Retina)屏幕是苹果公司"发明"的一个营销术语。 苹果公司将 dpr > 1
的屏幕称为视网膜屏幕。
2688 x 1242,
896 x 414,很容易得出 iPhone XS Max 的 dpr 为 3。
为不同 DPR 屏幕,提供恰当的图片
举个例子,同样的 CSS 像素大小下,屏幕如果有不同 DPR,同样大小的图片渲染出来的效果不尽相同。
dpr = 3 的手机为例子,在 300 x 389
CSS 像素大小的范围内,渲染 1倍/2倍/3倍 图的效果如下:
可以看到,在高 DPR 设备下提供只有 CSS 像素大小的图片,是非常模糊的。
为了在不同的 DPR 屏幕下,让图片看起来都不失真,我们需要为不同 DPR 的图片,提供不同大小的图片。
方案一:无脑多倍图
假设,在移动端假设我们需要一张 CSS 像素为 300 x 200
的图像,考虑到现在已经有了 dpr = 3 的设备,那么要保证图片在 dpr = 3 的设备下也正常高清展示,我们最大可能需要一张 900 x 600
的原图。
当然这样并不可取,会造成大量带宽的浪费。
方案二:媒体查询
方案二,我们可以考虑使用媒体查询。到今天,我们可以通过相应的媒体查询,得知当前的设备的 DPR 值,这样,我们就可以在对应的媒体查询中,使用对应的图片。
#id {
background: url(xxx@2x.png
}
@media (device-pixel-ratio: 2 {
#id {
background: url(xxx@2x.png
}
}
@media (device-pixel-ratio: 3 {
#id {
background: url(xxx@3x.png
}
}
这个方案的缺点在于:
- 要写的代码可能太多了,而且,可能存在一些介于 12,23 之间的 DPR 值,不好穷举出所有场景
- 需要注意语法需要的兼容性,需要添加前缀,譬如
-webkit-min-device-pixel-ratio
,当然这个可以由autoprefixer
辅助解决
方案三:CSS 配合 image-set 语法
image-set 属于 CSS background 中的一种语法,image-set(
函数为设备提供最合适的图像分辨率,它提供一组图像选项,每个选项都有一个相关的 DPR 声明,浏览器将从中选择最适合设备的图像进行设置。
.img {
/* 不支持 image-set 的浏览器*/
background-image: url('../photo@2x.png';
/* 支持 image-set 的浏览器*/
background-image: image-set(
url('./photo@2x.png' 2x,
url('./photo@3x.png' 3x
;
}
这样一看,作用应该很清晰了。对于支持 image-set
语法的浏览器:
- 如果其设备对应的 DPR 为 2,会选取这条
- 如果其设备对应的 DPR 为 3,会选取这条
url('./photo@3x.png' 3x
记录,也就是最终生效的 URL 是'./photo@3x.png'
;
url('./photo@2x.png' 2x
记录,也就是最终生效的 URL 是 './photo@2x.png'
;
2x,3x
就是用于匹配 DRP的。
image-set 的一些痛点与媒体查询方案类似。代码量与兼容性语法,而且难以匹配所有情况。
方案四:srcset 配合 1x 2x 像素密度描述符
简单来说,srcset 可以根据不同的 dpr 拉取对应尺寸的图片: