picture 标签是解决艺术指导、格式降级、多条件组合三类硬需求的原生方案,非 img 升级版;它不提速单图加载,但可避免错推高分辨率图、不支持格式或构图失当等问题。

picture 标签不是“更高级的 img”,而是解决 img 无法处理的三类硬需求的原生方案:艺术指导、格式降级、多条件组合。 它不提升单图加载速度,但能避免在手机上强塞 4K 图、在 Safari 13 上硬推 AVIF、或让竖屏用户看到被裁掉半张脸的横幅图——这些是 img 即使配上 srcset 和 sizes 也做不到的。
什么时候必须用 picture 而不是 img
当你要做以下任意一种事时,picture 是唯一合规且可靠的选择:
- 同一内容在不同设备上需要完全不同的构图(比如桌面显示全景,手机只保留人脸特写)
- 想默认提供
image/avif或image/webp,但必须确保 IE11、旧版 Safari 用户仍能看到image/jpeg - 既要按屏幕宽度选图,又要按格式支持选图,且二者不能混在同一个
srcset里(img的srcset不支持type)
误用场景:仅做分辨率适配(如 1x/2x)或简单尺寸切换(如 320w/768w/1200w)——这时直接用 img 的 srcset + sizes 更轻量、兼容性更好。
source 元素的匹配顺序决定一切
浏览器从上到下逐个检查 <source>,遇到第一个同时满足 media 和 type(如果写了)的就停止并加载,后续 <source> 完全忽略。这个“短路逻辑”是关键:
立即学习“前端免费学习笔记(深入)”;
- WebP 优先?把所有
type="image/webp"的<source>放最上面 - 小屏优先?把
media="(max-width: 480px)"的放最上面(注意不是 min-width) - 不要混用
media和type在同一行还指望浏览器智能合并——它只认“第一个完全匹配” -
<img>必须存在,且必须放在最后;它既是降级兜底,也是语义终点(无障碍工具只读这里)
常见错误:sizes 属性在 picture 里无效
sizes 只对 <img> 的 srcset 生效,**在 <source> 上写 sizes 是无效的**。很多人复制粘贴时把 img 的 sizes 错放到 source 上,结果浏览器根本不会根据视口宽度计算资源尺寸。
正确做法:
-
<source>只管“要不要加载这张图”(靠media或type) - 具体加载哪张分辨率的图,由该
<source>的srcset内部决定(例如srcset="hero-400w.jpg 400w, hero-800w.jpg 800w") - 如果你需要精确控制某张图在不同视口下的渲染宽度,得在对应
<source>的srcset里配好,而不是加sizes
兼容性与降级的实际底线
所有现代浏览器(Chrome 38+、Firefox 38+、Safari 9.1+、Edge 13+)都原生支持 picture。真正要小心的是:
- IE 完全不支持,且无 polyfill 能完美模拟
type匹配逻辑(picturefill.js只能模拟media) - 部分安卓 WebView(尤其 4.x)对
type属性识别不稳定,建议 WebP 后备至少保留一张 JPEG -
<img>的src必须是真实可访问路径,不能是占位符或空字符串,否则降级失败时页面留白
最容易被忽略的一点:<source> 的 srcset 值如果包含多个图片(如 "a.jpg, b.jpg 2x"),而其中某张图 404,整个 <source> 就算匹配成功也会加载失败,浏览器不会跳到下一个 <source> —— 所以每条 srcset 都得单独验证可用性。



















