解读响应式网页中的响应式图片srcset+sizes处理方案
发布于 作者:苏南大叔 来源:程序如此灵动~响应式图片的最好处理方案究竟是什么呢?动态更改图片的显示尺寸(width
/height
属性)么?还是要动态更改图片的地址?本文将要讨论其中的一个可能是最好的响应式图片方案:img
的srcSet
属性。
苏南大叔的“程序如此灵动”博客,记录苏南大叔和计算机代码的故事。事先说明的是,这个srcSet
的概念表面上看很好理解,但是图片切换的理由和时机就非常难以理解了。测试环境:firefox@108.0.1
,chrome@108.0.5359.125
。
测试环境
首先要声明一下本文的测试环境,谷歌浏览器vs火狐浏览器。本文的测试代码是img
的srcSet
属性。期待的测试结果是:代码会根据浏览器的情况(视口宽度或者密度比)的变化而变化。
然而,谷歌浏览器的情况不容乐观。虽然会根据情况第一时间选择合适的图片地址,但是存在的问题是会缓存这个图片选择结果。在页面刷新前,无论相关的实际情况如何变化,都不会再次更改图片,也就是失去了响应。目前【稍稍有点改善】的方法就是:打开谷歌浏览器的开发者模式,然后点击network
里面的“禁用缓存”选项(其他禁用缓存的方法无效)。
目前网络上的大部分攻略都表示:不知道选择某个图片的理由,是浏览器的自主行为。目前,使用市场上具有统治地位的谷歌浏览器就是无法解释,因为它的缓存结果太强大了,对srcSet
的支持不好。
所以,为了更好的理解srcSet
的工作原理,本文的测试环境破天荒的改为了火狐浏览器。在这个浏览器下面,可以最好的演示和理解整个图片切换过程。
基本框架原则
响应式图片方案就是在img
标签上面增加了特殊的srcSet
和sizes
来控制图片的显示的。例如:
<img src="0.png"
srcset="1.png 500w, 2.png 800w, 3.png 1200w"
sizes="(max-width:600px) 300px, 900px"
/>
- 图片是很多张图片(理论上来说区别是像素密度清晰度的不同),只是对这些图片进行了动态切换。
srcSet
属性,规定最基础的切换规则。尺寸的单位必须是w
(别的尺寸不生效),理解为日常最常用的px
。sizes
属性可以不规定,主要的切换逻辑都存在于srcSet
里面,它只是对srcSet
属性的切换条件的再加工。而且,sizes
内部使用px
单位,而不使用w
单位。
苏南大叔总结如下(经验总结,目前网络上无此描述):
srcset中的w为单位的数值 = 视口px宽度 * 硬件密度比
下面通过不同的例子来对上述原则,进行理解。
根据视窗宽度选择
根据视窗的宽度的不同来切换图片的地址属性,这个是非常经典的操作。css
通常也是利用media
媒体查询视口宽度,进而修改页面样式来实现响应式设计的。
本文中的所有图片真实的尺寸都是100px
宽。
img {
width: 100px;
}
第一个例子【推荐】
<img srcset="1.png 550w, 2.png 850w, 3.png 1050w" src="0.png" />
这段代码中,定义了三个图片地址,每个地址后面都(必须)使用w
单位定义了一个宽度。
上述例子中,宽度实际上就是个切换图片的临界值,规定的区间是:
视窗宽度区间 | 响应式图片的实际取值 |
---|---|
(0,550/像素比] | 1.png |
(550/像素比,850/像素比] | 2.png |
(850/像素比,1050/像素比] | 3.png |
(1050/像素比,正无穷大] | 3.png |
注意:取值区间一边是小括号,另外一边是中括号。像素比一般来说,电脑设备一般取值为1。而手机设备一般取值不为1。
第二个例子【败笔】【混乱】
第二个例子,在这个例子中,在srcSet
后面增加了一个没有规定w
的地址,导致全部逻辑被颠覆。
<img srcset="1.png 550w, 2.png 850w, 3.png 1050w, 4.png" src="0.png" />
测试结果:
所有的w
为单位的宽度值,
1)当密度比为1的时候,视口宽度只有确切的等于这个值(除以密度比1)的时候,才会显示对应的图片,而不是原来的区间。
2)当密度不为1的时候,表现为一个很奇怪的区间,真的很奇怪。
视窗宽度区间 | 响应式图片的实际取值 |
---|---|
(0,550/像素比] | 1.png |
(550/像素比,850/像素比] | 2.png |
(850/像素比,1050] | 3.png |
(1050,正无穷大] | 4.png |
根据密度比进行选择
在picture
的密度比切换方案测试中,失败了。但是在img
的密度比测试方案中,是成功的。而且恒定解释为一个区间,并不会出现解释为某个确切值的情况。
<img srcset="1.png 1x, 2.png 2x, 3.png 3x" src="0.png" />
实际的设备中,清晰度的衡量值:像素比并不恒定为整数。(用js
去监测的话,表现为window.devicePixelRatio
)
测试结果是:
像素比区间 | 取值 |
---|---|
(0,1] | 1.png |
(1,2] | 2.png |
(2,3] | 3.png |
(3,正无穷大] | 3.png |
这里如果在最后增加一个没有定义像素比的图片地址的话,无效直接忽略即可。
增加sizes
属性
sizes
属性就是来搅局的,只规定srcSet
属性就可以完美表述和切换了。但是,非要在这个srcSet
属性的基础上再叠加一个sizes
来再添变数。srcSet
不是规定的被选择的标准么?size
是规定选择的结果的,直接制定结果。
sizes
可以直接规定值,以w
为单位。实际上表述的值,和srcSet
中的以w
为单位的值,实际上是乘以密度比的关系。
sizes中的px值 * 密度比 = srcSet中的w值
测试例子如下:
<img
srcset="1.png 550w, 2.png 850w, 3.png 1050w"
sizes="(max-width:800px) 200px,600px"
src="0.png"
/>
这个表述的区间是:
实际像素比 | sizes规定:视口宽度px | 视同srcset中的值 | 落入srcset区间 | 最终结果 |
---|---|---|---|---|
1 | (0,800] | 200*像素比 | (0,550 | 1.png |
1 | (800,无穷大] | 600*像素比 | (550,850] | 2.png |
2 | (0,800] | 200*像素比 | (0,550] | 1.png |
2 | (800,无穷大] | 600*像素比 | (1050,无穷大] | 3.png |
3 | (0,800] | 200*像素比 | (550,850] | 2.png |
3 | (800,无穷大] | 600*像素比 | (1050,无穷大] | 3.png |
视窗宽度区间 | 响应式图片的实际取值 |
---|---|
(0,550/像素比] | 1.png |
(550/像素比,850/像素比] | 2.png |
(850/像素比,1050] | 3.png |
(1050,正无穷大] | 4.png |
无效或错误表述
以下都是无效或者错误表述:
错误一:没写默认的src
,兼容性。
<img srcset="1.png 550w, 2.png 800w"/>
错误二:srcSet
有个单独的无条件图片地址,会引起混乱。
<img srcset="1.png 550w, 2.png" src="0.png"/>
错误三:srcSet
中使用px
表述,无效。
<img srcset="1.png 550px, 2.png 800px" src="0.png"/>
错误四:srcSet
使用像素比表述时,定义了有个单独无效的表述,虽然不会导致混乱。
<img srcset="1.png 1x, 2.png" src="0.png"/>
错误五:sizes
表述中错误使用了w
单位,导致sizes
属性整体失效。
<img srcset="1.png 500px, 2.png 800px" sizes="600w" src="0.png"/>
错误六:使用像素比描述的时候,试图使用sizes
去改写条件,无效。
<img srcset="1.png 1x, 2.png 2x, 3.png 3x" sizes="(max-width:800px) 2x,1x" src="0.png"/>
js
检测手段
监测是否支持srcset
:
'srcset' in HTMLImageElement.prototype
'sizes' in HTMLImageElement.prototype
检测视窗宽度:
document.body.clientWidth
检测设备密度比:
window.devicePixelRatio
检测当前图片的src
:
document.getElementsByTagName("img")[0].currentSrc
相关链接
响应式图片的处理方案,已经有以下几种:
- https://newsn.net/say/js-retina.html
- https://newsn.net/say/html-img-srcset.html
- https://newsn.net/say/html-picture.html
看了很多文章,直到看到下面这篇文章,才明白更换浏览器的重要性。(不过,我这边的观点和这个链接文章也不一致)
结束语
苏南大叔经过不断的方案选择和对比,觉得picture
+source
的方案,更加好一些。毕竟谷歌浏览器里面也能顺利识别和流畅切换。更多html
标签的解读,请参考苏南大叔的文章:
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。