参考于 公众号前端早读课【第2908期】干货满满受益匪浅
干货太多了,这里总结一些可用性极强的用法供大家参考
Picture元素的使用、为不同的DPR屏幕提供合适的图片
Picture元素的使用
HTML5 规范新增了 Picture Element
<picture> 元素通过包含零或多个 <source>元素和一个 <img>元素为不同的显示 / 设备场景提供图像版本。浏览器会选择最匹配的子 <source>元素,如果没有匹配的,就选择 <img>元素的 src 属性中的 URL。然后,所选图像呈现在 元素占据的空间中。
<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>
简而言之, <picture>元素的作用:
- 通过<source>给出一系列对兼容性有所要求的现代图片格式选项
- 通过<img>给出兜底的高兼容性图片格式选项
- 浏览器通过对给出的图片格式做特性检测,要决定加载哪个 URL,user agent 检查每个<source>
- 的 srcset、media 和 type 属性,来选择最匹配页面当前布局、显示设备特征等的兼容图像。
- 最终,所选图像呈现在<img>元素占据的空间中
为不同 DPR 屏幕,提供恰当的图片
简单的计算公式:DPR = 物理像素 / 设备独立像素
为了在不同的 DPR 屏幕下,让图片看起来都不失真,需要为不同 DPR 的图片,提供不同大小的图片
方案一:无脑多倍图
在移动端假设需要一张 CSS 像素为 300 x 200 的图像,考虑到现在已经有了 dpr = 3 的设备,那么要保证图片在 dpr = 3 的设备下也正常高清展示,最大可能需要一张 900 x 600 的原图。不管设备的 dpr 是否为 3,我们统一都使用 3 倍图。
当然这样并不可取,会造成大量带宽的浪费。
方案二:媒体查询
可以通过相应的媒体查询,得知当前的设备的 DPR 值。这样,我们就可以在对应的媒体查询中,使用对应的图片。
这个方案的缺点在于:
- 要写的代码可能太多了,而且,可能存在一些介于 12,23 之间的 DPR 值,不好穷举出所有场景
- 需要注意语法需要的兼容性,需要添加前缀,譬如 -webkit-min-device-pixel-ratio,当然这个可以由 autoprefixer 辅助解决
#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)
}
}
方案三: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
);
}
方案四:srcset 配合 1x 2x 像素密度描述符
<div class='illustration'>
<img src='illustration-small.png' srcset='images/illustration-small.png 1x,images/illustration-big.png 2x'/>
</div>
上面 srcset 里的 1x,2x 表示 像素密度描述符,表示
- 当屏幕的 dpr = 1 时,使用 images/illustration-small.png 这张图
- 当屏幕的 dpr = 2 时,使用 images/illustration-big.png 这张图
- 如果不支持 srcset 语法,src='illustration-small.png' 将会是最终的兜底方案
方案五:srcset 属性配合 sizes 属性 w 宽度描述符
上述 3 种方案都存在统一的问题,只考虑了 DPR,但是忽略了响应性布局的复杂性与屏幕的多样性
<img sizes = "(min-width: 600px) 600px, 300px" src = "photo.png" srcset = "photo@1x.png 300w,photo@2x.png 600w,photo@3x.png 1200w, " />
sizes = "(min-width: 600px) 600px, 300px" 的意思是:
- 如果屏幕当前的 CSS 像素宽度大于或者等于 600px,则图片的 CSS 宽度为 600px
- 反之,则图片的 CSS 宽度为 300px
srcset = “photo@1x.png 300w, photo@2x.png 600w, photo@3x.png 1200w 里面的 300w,600w,900w 叫宽度描述符。
当前屏幕 dpr = 2 ,CSS 宽度为 375px。
当前屏幕 CSS 宽度为 375px,则图片 CSS 宽度为 300px。分别用上述 3 个宽度描述符的数值除以 300。
- 300 / 300 = 1
- 600 / 300 = 2
- 1200 / 300 = 4
上面计算得到的 1、 2、 4 即是算出的有效的像素密度,换算成和 x 描述符等价的值 。这里 600w 算出的 2 即满足 dpr = 2 的情况,选择此张图。
当前屏幕 dpr = 3 ,CSS 宽度为 414px。
当前屏幕 CSS 宽度为 414px,则图片 CSS 宽度仍为 300px。再计算一次:
- 300 / 300 = 1
- 600 / 300 = 2
- 1200 / 300 = 4
因为 dpr = 3,2 已经不满足了,则此时会选择 1200w 这张图。