浏览器按顺序选择第一个匹配的<source>,而非最优解;media必须完整、sizes不可缺、type需服务器配合,否则静默回退到<img src>。

浏览器只认第一个匹配的 <source>
写再多 <source> 也没用,浏览器从上到下扫描,遇到第一个同时满足 media 和/或 type 的就立刻加载它的资源,后面所有 <source> 全部跳过。这不是“多选”,是“短路匹配”。
常见错误包括:
-
media="(max-width: 768px)"写在最前面 → 小屏、中屏、大屏设备全走这条,宽屏规则永远不触发 - 断点重叠,比如
(max-width: 768px)和(min-width: 768px)→ 在恰好 768px 宽时行为不可控,浏览器只取第一个 -
media="768px"(漏括号)→ 整个<source>被忽略,不报错也不警告
<source> 的 srcset 不支持 x 描述符
你在 <source> 的 srcset 里写 photo@2x.jpg 2x,浏览器直接无视 —— 它只按 media 或 type 匹配后取第一个可用资源,DPR(设备像素比)适配完全交给最外层 <img> 的 srcset 处理。
正确做法是:
立即学习“前端免费学习笔记(深入)”;
- 每个
<source>的srcset只用w描述符(如photo-400w.jpg 400w),并配好sizes - 或者干脆只写单图路径(
srcset="photo-sm.jpg"),把 DPR 适配全交给后面的<img> - 如果要用
x,必须放在<img>的srcset里,且<img>的src必须存在(作为 1x fallback)
<img> 不是可选项,是强制兜底节点
<picture> 本身不渲染任何内容,也不发任何请求;没有 <img>,整个结构就是空的。即使所有 <source> 都匹配失败,浏览器也只会静默回退到 <img>,不会报错、不会提示、也不会尝试下一个 <source>。
必须确保:
-
<img>放在<picture>最末尾 -
<img>至少有src和alt属性 -
<img>的srcset和sizes是独立生效的 —— 它只在所有<source>都不匹配时才起作用 - 服务器返回的图片 Content-Type 必须和
<source>的type完全一致(image/webp≠image/jpg),否则该<source>直接被跳过
真正难调的不是语法,是运行时环境
本地测试看着没问题,上线后部分设备只加载 fallback 图?大概率不是代码写错了,而是这些地方出了问题:
- CDN 或反向代理没透传
Accept请求头 → 浏览器声明支持image/avif,但服务端根本收不到,返回了 JPEG,Content-Type 却还是image/jpeg,导致type="image/avif"匹配失败 - 某些 Android WebView 声称支持
image/avif,但实际解码崩溃 → 页面空白,Network 面板里看不到请求,只能靠真机抓包确认 - CSS 中设了
width: 300px,但sizes写成"100vw"→ 浏览器预估图宽远大于实际,可能加载 2MB 的大图却只显示 300px 宽 - Chrome 120+ 对
min-resolution: 2dpi这类写法更严格,得改用2dppx



















