1. img标签的srcset属性
2. 响应式图片示例
来自腾讯IMweb团队的响应式图片示例。核心代码是:
<img srcset="https://coding.imweb.io/demo/p3/responsive/img/large.png 960w,https://coding.imweb.io/demo/p3/responsive/img/medium.png 640w, https://coding.imweb.io/demo/p3/responsive/img/small.png 320w">
代码的含义很好理解,我们向浏览器声明了包含 960像素、640像素、320像素 三种宽度的 候选图片列表,由浏览器根据当前CSS像素宽度,加载最适合的图片,实现图片的响应式。
打开Chrome,F12调出开发者工具,点Toggle device toolbar,将开发者工具放到屏幕右侧,拖动屏幕边缘到最小(低于320像素),然后刷新页面,从小到大拉宽浏览器,看浏览器加载图片宽度的变化,可以看到:
默认浏览器加载320px图片,当浏览器窗口宽度分别达到320像素时,640像素时,依次加载了640px和960px的图片。
是不是很好理解呢?
特别地,Chrome会缓存加载的图片,当图片被缓存到浏览器中的时候,Chrome会优先加载较大较为清晰的图片。
原因很好理解,既然图片已经被存储到本地,那么无需考虑流量和加载时间,为用户提供越清晰的图片越好。
3. DPR影响Chrome从 srcset 选择图片
DPR,全称是devicePixelRatio,DPR = 设备像素 / CSS像素(某一方向上)
点F12的device toolbar最右侧的三个点,选择 add device pixel ratio,可见顶部显示 DPR1.0(如果你之前没有调过)
此时,设备宽度等于CSS宽度。
试着把DPR改成2.0,然后再次将出屏幕边缘拖到最小,然后点击右侧的Network标签,选择Disable cache(清除缓存,忽略缓存对Chrome选择加载图片的影响)。此时再次将屏幕边缘从小向右拖动到最大。
根据设想,因为DPR变成了2.0,此时,当浏览器窗口宽度分别达到原来的一半时,会依次加载不同像素的图片。
即浏览器宽度最小时,默认加载320像素的图片,当浏览器宽度达到320像素和480像素,依次加载640px和960px的图片。
但事实并非如此:
当DPR为2.0时,当浏览器窗口宽度达到 227像素、393像素时,就依次加载了640px和960px的图片。
当DPR为3.0时,当浏览器窗口宽度达到 151像素、261像素时,就依次加载了640px和960px的图片。
实际加载的图片,并不是简单的除以2,或者除以3。
4. 如何预测不同DPR下不同设备宽度,Chrome会加载哪张图片呢?
首先,当DPR为1.0的时候,浏览器会根据srcset中声明的宽度,加载小于或等于当前设备宽度的图片。
并且,srcset中,有候选图片已经被浏览器缓存,即使当前设备宽度,应该加载更小的图片,但缓存中有更大的图片,会优先加载缓存中的图片。
此外,根据第三方资料(未核实),当设备网速较慢或流量上网(流量费用高),此时Chrome会一直加载最小的图片,以帮助用户节省流量,快速浏览。
当DPR不为1.0的时候呢?
先来搞清楚,浏览器时如何判断更换图片的临界值吧!
回到标题3中列举的事实:
当DRP为2.0时,此时设备宽度是CSS宽度(浏览器窗口宽度)的2倍。
当浏览器窗口宽度为161像素时,设备宽度为 161 * 2 = 322 像素,大于320像素,此时浏览器应该加载 640px 图片,但事实是:
当浏览器窗口宽度为227像素时,设备宽度为 227 * 2 = 457 像素,大于320像素,此时浏览器才从320px 图片,切换到了 640px 图片。
更有意思的是:
当浏览器窗口宽度为393像素时,设备宽度为 393 * 2 = 786 像素,并没有大于 960像素,此时浏览器却从 640px 图片,切换到了 960px 图片。
情况似乎比DPR为1.0的时候复杂很多。
5. Chrome从srcset中选择图片的规则
腾讯IMweb团队shijisun老师为我们揭开了规则的面纱:
让我们选择浏览器窗口宽度的像素节点,来做分析:
(1)DPR2.0,浏览器窗口宽度为 226 像素时,设备宽度 为 226 * 2 = 452 像素,此时 320/452 = 0.7079646,452/640 = 0.70625,前者 大于 后者,所以浏览器加载了 320px 图片。
(2)DPR2.0,浏览器窗口宽度为 227 像素时,设备宽度 为 227 * 2 = 457 像素,此时 320/457 = 0.7002189,
457/640 = 0.7140625,后者 大于 前者,所以浏览器加载了 640px 图片。
大家发现规律了吗?
Chrome选择图片时,是根据 设备宽度与图片宽度(srcset中声明的宽度)的比值:
当设备宽度小于图片宽度时,设备宽度/图片宽度
当设备宽度大于图片宽度时,图片宽度/设备宽度
优先选择 比值较大 的图片
让我们验证一下:
(1)DPR3.0,浏览器窗口宽度为 150 像素时,设备宽度 为 150 * 3 = 450 像素,此时 320/450 = 0.7111111,450/640 = 0.703125,前者 大于 后者,所以浏览器加载了 320px 图片。
(2)DPR3.0,浏览器窗口宽度为 151 像素时,设备宽度 为 151 * 3 = 453 像素,此时 320/453 = 0.706401,
453/640 = 0.7078125,后者 大于 前者,所以浏览器加载了 640px 图片。
验证成功!
目前,关于浏览器如何根据srcset加载图片,并没有标准,依赖于浏览器自己的选择策略。截止到2019年10月17日,该策略在Chrome 79.0.3942.0(正式版本)canary有效!
感谢腾讯IMweb的shijisun老师发现规则,并指导作者撰写此文!