Whidy Writes

响应式图片中srcset遇到的问题

发布于:

准备工作

请先打开我修改后的Demo,并阅读MDN-响应式图片,基本了解 HTML + CSS 响应式图片的方法后,进行阅读。

首先我们已经知道,实现响应式图片的两种方式:使用 srcset 以及 <picture> 元素,来实现网页中的响应式图片处理方法。这两种方式的具体细节这里不复述了,可阅读上面提到的MDN文档。

诡异的响应式失效了

我在做测试的时候,发现我通过 srcset 设置的响应式图片功能并没有按照设定选择性加载图片。我是通过开启开发者工具面板,将面板固定在右侧,并左右拖动面板宽度来改变文档可视宽度进行测试。然而无论可是区域多大,在网络(Network)标签中看到始终加载 elva-fairy-800w.jpg 图片,而实际上设定的规则当视口宽度小于或等于 600px 时,应当加载 elva-fairy-480w.jpg 小一点的图片。

为了方面理解,该部分的代码如下:

<img srcset="https://mdn.github.io/learning-area/html/multimedia-and-embedding/responsive-images/elva-fairy-480w.jpg 480w, https://mdn.github.io/learning-area/html/multimedia-and-embedding/responsive-images/elva-fairy-800w.jpg 800w" sizes="(max-width: 600px) 480px, 800px" src="https://mdn.github.io/learning-area/html/multimedia-and-embedding/responsive-images/elva-fairy-800w.jpg" alt="Elva dressed as a fairy">

而我也考虑过是否是浏览器问题,故而用 Safari 测试,依然无效,这就非常奇怪了!接下来,我死磕精神再犯。。。

测试方法

起初是配合MDN的Demo进行研究,为了更好的调试,我在原Demo上添加了一段CSS样式,借此证明,不同浏览器在媒体查询是没有问题的,我添加的CSS如下:

/* 配合测试增加的媒体查询 */ @media screen and (max-width: 600px) { body { color: red; } }

这段媒体查询和 srcset 内的设置宽度一致,当HTML文档宽度小于等于 600px 时,字体变为红色。方法上面已经提到,通过开启开发者模式面板置于右侧,拖动面板宽度来控制文档宽度显示的方法。

现象

我们先看下 ChromeSafari 浏览器网络面板中的图片加载情况:

浏览器网络面板图片请求结果对比 {responsive-image-dev-tips-network.jpg,1010w}

此时文档可视区域宽度小于600px,故而整体文字颜色均为红色,说明CSS的媒体查询正常。

在图片加载情况,因为Demo中使用了两种响应式图片方案。

picture元素方式

picture元素的规则是小于800px时,加载 elva-480w-close-portrait.jpg ,源码如下。

<picture> <source media="(max-width: 799px)" srcset="https://mdn.github.io/learning-area/html/multimedia-and-embedding/responsive-images/elva-480w-close-portrait.jpg"> <source media="(min-width: 800px)" srcset="https://mdn.github.io/learning-area/html/multimedia-and-embedding/responsive-images/elva-800w.jpg"> <img src="https://mdn.github.io/learning-area/html/multimedia-and-embedding/responsive-images/elva-800w.jpg" alt="Chris standing up holding his daughter Elva"> </picture>

虽然Demo中媒体查询的分界点是 800px ,但是并不影响。从上图中也能发现,这个加载是正常的。

srcset方式

问题就出在 srcset 方式,依照代码规则,理论上应当加载的图片是 elva-fairy-480w.jpg ,源码如下:

<img srcset="https://mdn.github.io/learning-area/html/multimedia-and-embedding/responsive-images/elva-fairy-480w.jpg 480w, https://mdn.github.io/learning-area/html/multimedia-and-embedding/responsive-images/elva-fairy-800w.jpg 800w" sizes="(max-width: 600px) 480px, 800px" src="https://mdn.github.io/learning-area/html/multimedia-and-embedding/responsive-images/elva-fairy-800w.jpg" alt="Elva dressed as a fairy">

然而在网络面板中的两个主流浏览器都是加载了 elva-fairy-800w.jpg ,无论我怎么缩放,最早发现这个问题是在我自己上线了响应式图片后,我的站点图片加载不符合预期,现在这个Demo都出问题了,就说明并非单纯的是我的代码上的问题。

思考

那究竟是为什么一切代码都是正常的,但是srcset方式的响应式图片失败了呢?

我不断查阅 srcset 相关的文档, 媒体查询 规则是否错误,甚至是 视口宽度 的判定规则等等。我渐渐意识到srcset方式理解的视口宽度或许不太一样。于是我进一步进行各种测试:

模拟移动端

这个测试完全符合预期,如图:

模拟移动端下网络面板图片请求 {responsive-image-dev-tips-network-2.jpg,799w}

当然测试过程中需要注意的两点:

  1. html中header内的viewport默认<meta name="viewport" content="width=device-width">
  2. 请注意模拟移动端时DPR的值设置为1

既然模拟移动端都没有问题就暂时不去做物理设备的抓包检测了。

那么新的问题,难道模拟移动端的视口宽度和缩放浏览器的视口宽度判定有差异!?

视口宽度

视口 (viewport) 代表当前可见的计算机图形区域。在 Web 浏览器术语中,通常与浏览器窗口相同,但不包括浏览器的 UI, 菜单栏等——即指你正在浏览的文档的那一部分。

上面是MDN官方解释,其实一直以来我的理解就是HTML文档展示(可见)的宽度,到现在为止我觉得我的理解仍然没有错误。因为我开始一度怀疑媒体查询在srcset下差异是根据screen的宽度(也就是设备或者说是显示器当前分辨率)为准,但是很显然这个想法不太正常,在媒体查询和HTML规则设计也不应当存在这种奇怪的差异。

最后的尝试

此刻的我濒临绝望,为这个小东西研究了两三天,人生不值得。人生有时候要学会舍弃,不纠结。。。

  • 但是我仍然试着去Google搜索 srcset viewport width 之类的关键词。并未收获。
  • 我把Demo页面发去旁边的MM的电脑上测试,竟让是正常的,我震惊了

到底发生了什么?!

该死的设备

我自用的开发电脑 MacBook Pro 2018 ,难道是屏幕出了问题,我知道MacBookPro都是Retina屏,可能分辨率会收到影响,但是在做媒体查询测试的时候,其他的媒体查询(CSS和picture)都是正常的,也很难说得过去,我试着调整屏幕的分辨率,原始分辨率,缩放模式等等,依然无效。

我找来一个外屏接上,组成双屏,继续测试。神奇的一幕出现了,我的外屏是1080P的普通显示器,在这台显示器上测试,和之前在MM电脑上测试的结果一致,符合预期!

最最最离谱的事情(我还在纠结,这就是我的命吧。),也许有人会觉得我真的很无聊竟然会采用这个测试方法。想看高清版本的,也可以上youtube查看:img srcset on macbookpro not works

上面是一段视频,不知道如何录屏双屏,只能用手机拍,效果不太好,但勉强也能看,所以解释一下视频操作:

  1. 将Demo页面放在外接屏(1080P上),刷新页面看到网络面板中请求正确,为elva-fairy-480w.jpg
  2. 将浏览器移至MacBookPro内屏,在移入成功的瞬间,发起了网络请求,加载了elva-fairy-800w.jpg,但是其他媒体查询的样式未发生变化。

因此可见,在页面的屏幕发生改变的时候,会触发 srcset 的变化。但是这是为什么呢?

我决定还是去Stack Overflow问问看,Why srcset not work normally on MacBookPro(or maybe retina monitor caused?),看看有没有人能够一起讨论。

结论

我最后依然不知道发生了什么,只知道viewport的一些设定大部分起初设计是为了在不同设备上进行显示优化的。而我所做的这个响应式图片的功能和代码其实是没有问题的,我觉得我和这个问题无缘,自然是解不出来的。以斯多葛哲学理论为目标,暂时放下该放下的。我已经尽力了。

写了这么多内容,其实这篇文章并没有很多的营养,而真实的需要注意的就是可能在Retina屏幕或者说MacBookPro设备下进行srcset的响应式图片研究学习开发测试中,会有大坑。做个笔记,也许有人遇到过这样的问题,但愿你能在第一时间搜到这个文章,停止做无效的研究和测试,当然要是发现了并解决了问题分享出来一起讨论更是一件开心的事情了。

参阅的文档

avatar

whidy

一名爱折腾的前端开发工程师,喜欢打篮球和分享 ฅʕ•̫͡•ʔฅ