响应式图片 · 让浏览器挑对那一张
<img src> 只能指向一个文件,而这个文件要同时满足三类互相冲突的屏幕:像素密度从 1 到 3 不等、布局宽度从手机的 360px 到桌面的 1440px 不等、网络从光纤到弱信号不等。按桌面 2x 屏准备的 2160px 图,落在 360px 宽的 2x 手机上是所需像素的 9 倍;按手机准备的 720px 图,放到桌面栏宽里又明显发虚。
浏览器最早能做的只有下载 src。2012 到 2014 年间,srcset(Apple 提出)与 <picture>(社区提出)两套方案在 WHATWG 与 W3C 之间争论了两年,最后合并成今天的形态:srcset 列候选、sizes 报布局宽度、<picture> 负责 art direction 与格式协商。此后十年又陆续补上 loading="lazy"、宽高比映射、fetchpriority,直到 2026 年三家引擎全部落地的 sizes="auto",把「布局宽度」这项最难手写的输入交还给布局本身。
每页都把属性设到真实的 <img> 上,候选图由 canvas 现画、图上印着自己的像素宽,浏览器选中哪一张既能看到,也由 currentSrc 回读。正文里的选择结果与像素值均出自 Chrome 154 的实测;其中几处与规范文本或常见说法不符,分别在 w 描述符与 sizes、sizes="auto" 与 loading 三页写明。
问题与来历
一张图为什么不够用,以及 srcset 与 <picture> 两条路线如何从对立走到合并。
选择哪一张
浏览器在下载之前就要定下候选:x 描述符对应像素密度,w 描述符配合 sizes 对应布局宽度,sizes="auto" 让布局给出宽度,<picture> 在更上一层按媒体条件与格式切换来源。
x 描述符与像素密度
x 描述符按 devicePixelRatio 选图,只适用于布局宽度固定的图。选中的候选会改写天然尺寸:400px 宽的 2x 图,naturalWidth 是 200。实测的取档规则是不小于 DPR 的最小密度。
w 描述符与 sizes
w 描述符写出候选的像素宽,sizes 写出布局宽度,两者之比即密度。sizes 是一份手抄的 CSS,抄错时浏览器照错的选;内存缓存里已有的大图会优先复用。
sizes="auto":让布局给出宽度
sizes="auto" 让懒加载的图直接取布局宽度选图,不再手抄 CSS。它只在 loading="lazy" 时生效,随附的 contain: size 会抹掉图片的宽高比,不写宽高时高度停在 150px。
picture 与 source:换图与格式协商
<source> 的 media 与 type 是命令而不是提示,第一个满足条件的必须采用。media 做 art direction,type 做格式协商,都不读文件内容;各分支的宽高写在 <source> 上。
何时加载、怎样占位
选定之后还有三个问题:下载前盒子该占多大、屏外的图何时开始下载、首屏的图如何抢到带宽与解码时机。
尺寸与占位:width、height 与 object-fit
width / height 映射为 aspect-ratio: auto w / h,图片下载前就按比例占位。属性只需给出比例,写错时图片自身的比例在加载后接管;盒子比例固定时由 object-fit 决定内容怎样落入。
loading:懒加载的提前量
loading="lazy" 把下载推迟到图片接近视口,提前量由浏览器决定,实测纵向 1250px、横向 625px。不写尺寸的懒加载图全部塌在一处,第一轮就全部下载。
优先级与解码:fetchpriority、preload 与 decoding
首屏主图还要争抢带宽与主线程。fetchpriority 调整请求优先级,preload 配 imagesrcset 让藏起来的图提前被发现,img.decode() 处理字节到齐之后的解码时机。
其余属性与 CSS 侧
alt、crossorigin、referrerpolicy、usemap 等不参与选择的属性,已废弃的表现属性,以及 CSS 里的 image-set()。
推荐方案
按首屏主图、正文配图、缩略图网格、art direction 四种场景给出可直接照抄的写法。
相关链接
规范
-
HTML · Images
WHATWG
srcset/sizes的语法与解析算法、选择图片来源、对环境变化的响应。本系列引用的"规范现行文本"均取自此处(核对于 2026-09)。 -
HTML · The img element
WHATWG
<img>的全部内容属性,以及allows auto-sizes的定义。 -
HTML · Lazy loading attributes
WHATWG
loading属性、脚本禁用时不懒加载的反追踪理由,以及 lazy load scroll margin 的实现建议。 -
HTML · Rendering · Images
WHATWG
img:is([sizes="auto" i], [sizes^="auto," i])的 UA 样式:contain: size与contain-intrinsic-size: 300px 150px。
讨论与史料
-
Add "auto sizes" for lazy-loaded images · whatwg/html#4654
GitHub
sizes="auto"的起点(2019-05),脱胎于 lazySizes 的data-sizes="auto"。 - Add sizes=auto to lazy-loaded <img> · whatwg/html#8008 GitHub 规范 PR,2023-06 合入。
-
sizes="auto, 100px" loading="eager" · whatwg/html#10110
GitHub
eager 图片上
auto应当被忽略还是等于100vw的讨论,与 Chrome 154 的实测行为有关。 -
sizes=auto images shouldn't use concrete object width · whatwg/html#12248
GitHub
object-fit: contain下 concrete object size 会随图片宽高比变化,可能引出二次选择。 - Responsive Images: How they Almost Worked and What We Need A List Apart · Mat Marquis 2012-01 的这篇文章把问题摆上台面,随后促成了 Responsive Images Community Group。
-
Bringing Responsive Images to Browsers
A List Apart · Mat Marquis
2014-04 为 Yoav Weiss 在 Blink 中实现
<picture>发起的众筹。 -
Srcset and sizes
ericportis.com · Eric Portis
w描述符与sizes的经典讲解,"浏览器在知道布局之前就要选图"的论证出处。
MDN
- <img> MDN 全部属性与兼容性矩阵。本系列的兼容性断言以 MDN BCD 为准。
- Using responsive images in HTML MDN 分辨率切换与 art direction 两类问题的入门讲解。
- image-set() MDN CSS 背景图的分辨率与格式切换。
同站
-
替换元素的 baseline
同站
<img>作为行内替换元素时底部多出的几像素,本系列不再重复。 - 图片预览 同站 缩略图与大图分离时的预加载与过渡。