响应式图片:理解 srcset、sizes 与设备像素比
srcset 列出可用图片文件。使用宽度描述符时,sizes 说明图片预期占用的 CSS 像素宽度,浏览器结合设备像素比及自身策略选择资源。实际布局仍由 CSS 决定。
本指南内容
图片看起来正常,并不代表下载量合理。页面可能下载远超显示需求的像素,也可能把小图拉伸到高像素密度屏幕上。响应式标记把生成的图片文件与页面中的显示空间联系起来,两者描述同一布局时才真正有效。
先从一个实际组件和几个有意义的图片尺寸开始。本文示例的内容栏最大宽度为 800 CSS 像素,窄屏左右各留 16 像素。所有候选图片使用相同构图,宽高比均为 4:3。
区分源文件像素、CSS 像素与 DPR
宽 800 像素的图片,不必在页面上占据 800 CSS 像素。浏览器可以把它显示在宽 400 CSS 像素的区域内。设备像素比为 2 时,这个区域横向约对应 800 个设备像素。这是分辨率规划关系,浏览器仍有权决定最终加载哪个资源。
先计算示例组件的显示宽度:取 800 与视口宽度减去 32 两者中的较小值,再乘以 DPR,得到可参考的源图片宽度。如果图片只占狭窄内容栏,就不应直接把整个视口宽度乘以 DPR。
| 视口宽度 | CSS 显示宽度 | DPR | 目标源宽度 |
|---|---|---|---|
| 392 | 360 | 1 | 360 像素 |
| 392 | 360 | 2 | 720 像素 |
| 1024 | 800 | 1 | 800 像素 |
| 1024 | 800 | 2 | 1600 像素 |
布局宽度变化时,使用宽度描述符
w 描述符表示文件本身的像素宽度,既不是媒体查询断点,也不能随意填写。sizes 告诉浏览器当前布局预期的显示宽度。下面的标记在视口不小于 832 CSS 像素时使用 800 像素显示区域;更窄时则扣除两侧边距。
示例 CSS 也是约定的一部分。如果以后把组件放进半宽网格,应同步修改 sizes。保留旧的全宽描述,可能让浏览器选中不必要的大文件。准确的 sizes 是对真实布局的描述,不是热门屏幕宽度的集合。
<img
src="/images/workspace-800.webp"
srcset="/images/workspace-400.webp 400w,
/images/workspace-800.webp 800w,
/images/workspace-1600.webp 1600w"
sizes="(min-width: 832px) 800px, calc(100vw - 32px)"
width="1600" height="1200"
alt="A desk with a monitor and an open notebook"
style="display:block;width:calc(100vw - 32px);max-width:800px;height:auto;margin-inline:auto"
>先估算候选资源,再检查实际选择
在宽 392、DPR 为 2 的视口中,显示区域为 360 CSS 像素,目标源宽度为 720。因此,在给定文件中,800w 是合理的预期选择。宽屏 DPR 为 2 时,目标为 1600。计算解释了选择的输入,但不能强制浏览器一定下载某个候选文件。
浏览器还可能考虑其他因素。缩小窗口后,它可能继续使用已经下载的大图。测试时应先选好设备设置,再使用新页面环境或重新加载,然后在开发者工具中查看最终图片 URL 与传输字节。反复缩放同一个已预热页面,容易得出错误结论。
候选列表也要求构建流程真正生成对应文件。生成 400、800、1600 像素版本,检查画质并确认每个 URL 都返回图片。不能把同一个 1600 像素文件复制改名,再给它们贴上不同的 w 标签;这种做法没有降低真实下载或解码成本。
- 检查元素的实际渲染宽度,不要默认它等于视口宽度。
- 把 currentSrc 选中的地址与网络面板中的响应对照。
- 核查文件尺寸、响应类型、缓存状态和传输字节。
- 在窄屏和宽屏下分别检查 DPR 1 与 DPR 2。
- 观察加载前后是否出现横向溢出或布局移动。
固定显示尺寸的图片可使用密度描述符
对于始终以固定宽度显示的小标志,可以改用 x 描述符。例如显示宽度为 120 CSS 像素时,提供宽 120 的 1x 文件和宽 240 的 2x 文件。这些是同一固定显示尺寸的不同分辨率版本;不要在同一个 srcset 中混用 x 与 w。
改变裁剪属于另一个设计问题。移动端需要脸部特写,而桌面端需要宽场景时,可通过 picture 和适当的媒体条件实施美术指导。本文主例使用相同构图,仅改变分辨率。替代文本应描述读者真正获得的有意义内容,而不是重复文件名或候选宽度。
<img src="/images/mark-120.png"
srcset="/images/mark-120.png 1x, /images/mark-240.png 2x"
width="120" height="120" alt="Example project mark">同时规划宽高比与加载时机
width 和 height 属性帮助浏览器在图片到达前按宽高比预留空间。CSS 改变显示宽度后,它们并不强迫图片维持原始 CSS 尺寸。示例宽高比为 4:3,因此显示宽 800 时高 600,显示宽 360 时高 270。保持比例可以避免图片变形。
长页面下方图片适合延迟加载,但不应不分位置地推迟首屏重要图片的请求。应根据组件使用位置决定。候选分辨率减少多余像素,合适的压缩、格式及加载策略则分别处理其他开销,不能互相代替。
原始图像内存与网络文件大小也不同。压缩后的 WebP 文件可能很小,解码后的像素缓冲区却大得多。图像内存计算器使用解码尺寸,网络成本则应测量实际压缩文件,不能仅凭像素数量推断字节。
发布前检查组件与生成文件是否一致
把布局规则和图片生成规则作为一个明确约定保存。记录候选宽度、裁剪、比例、压缩质量和 sizes 表达式,便于以后一起修改。最大宽度从 800 改为 1000 像素时,应重新审查候选资源,而不是只改样式。
发布前检查回退 src、所有 srcset 地址、替代文本和预留空间。用 CSS 到设备像素计算器复现自己的显示宽度和 DPR,再用宽高比计算器规划高度。若边距是固定 CSS 值,就不要只写 100% 作为 sizes 来代替真实表达式。
组件评审应说明测试时的页面布局,而不仅列出设备名称。同一手机横屏、竖屏或浏览器缩放状态可能产生不同显示宽度。保留实际截图和网络记录,后续修改时才能比较是否只是候选变化,还是布局规则已经变化。测试中命中缓存也要明确记录,避免把缓存带来的零传输误认成图片压缩效果。
常见问题
sizes 会改变图片的 CSS 宽度吗?
不会。使用宽度描述符时,它为资源选择描述预期显示区域。实际布局由 CSS 控制,两者应保持一致。
缩小窗口后为什么仍使用大图?
浏览器可能复用已经下载的资源。应在目标视口和 DPR 下重新加载,再检查选中的地址及网络传输,不要只观察一次窗口缩放。
2x 图片的文件大小总是两倍吗?
不是。宽高都翻倍会产生四倍像素,但编码字节还取决于画面内容、格式和压缩质量。应实际测量生成文件。
来源与定义
方法核验日期: