Chrome选择srcset中图片的规则

2019-10-17 11:56:10

青色的Google Chrome浏览器概念图

1. img标签的srcset属性

HTML5中img标签新增了一个 srcset 属性,通过设置该属性,可以为同一标签设置不同的图片源,格式为一组用逗号分隔的url,不同url后跟不同的宽度描述符(w)或像素描述符(x)。后者被用来描述url对应图片的像素密度信息,供浏览器参考。从而实现,当浏览器根据不同的屏幕分辨率,加载不同的图片,从而节省时间、流量消耗。


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老师发现规则,并指导作者撰写此文