标签仅在页面加载时静态选择一个最匹配的 ,不会动态响应 dpr 变化、窗口缩放或 zoom;真正动态切换需 javascript 主动监听并替换 的 src。

<picture></picture> 标签本身不负责“切换”,它只在页面加载时根据条件(如设备像素比、视口宽度)**静态选择一个最匹配的 <source></source>**,之后不会动态响应缩放、窗口 resize 或 DPR 变化。所谓“无缝切换”是常见误解——浏览器选完图就固定了,不会像 JS 那样监听 window.devicePixelRatio 并实时换图。
为什么 <picture></picture> 不会动态切换多倍图
浏览器解析 <picture></picture> 是一次性行为:在资源发现阶段(fetch phase),依据当前 srcset + sizes + 当前设备 DPR/宽度,选出一个最优 <source></source>,然后只加载那一张。后续 DPR 改变(比如从 1x 切到 2x 的外接屏)、窗口缩放、甚至用户 zoom 页面,都不会触发重选或替换 <img> 的 src。
- Chrome/Firefox/Safari 均如此,这是 HTML 规范明确要求的行为
- 你用 DevTools 强制修改
window.devicePixelRatio,也不会让已渲染的<picture></picture>重新选源 - 真正“动态切换”必须靠 JavaScript 主动监听并替换
<img>的src属性
<picture></picture> 正确写法:覆盖主流 DPR 场景
虽然不能动态切换,但合理配置 <source></source> 能让多数设备首次加载就拿到合适分辨率的图。关键不是堆 2x/3x,而是结合 sizes 和视口断点:
<picture><source media="(min-width: 768px)" srcset="hero-1200w-1x.jpg 1x, hero-1200w-2x.jpg 2x"><source media="(max-width: 767px)" srcset="hero-400w-1x.jpg 1x, hero-400w-2x.jpg 2x"> @@##@@ </source></source></picture>
- 每个
<source></source>的media先筛视口,再在该条件下按 DPR 选srcset中的对应项 -
<img src="hero-400w-1x.jpg" alt="hero">是 fallback,必须存在,且其src应与最低优先级<source></source>的 1x 图一致 - 避免写
1.5x或2.5x—— 大部分浏览器只认整数倍(1x,2x),Safari 对非整数支持不稳定
真要动态响应 DPR 变化?用 JS 监听并手动换图
如果业务强依赖“窗口拖到高分屏后立刻换 2x 图”,就得放弃 <picture></picture> 的声明式逻辑,改用脚本控制:
- 监听
matchMedia('(resolution: 2dppx)')的change事件(注意 Safari 需要加-webkit-前缀) - 更可靠的是轮询
window.devicePixelRatio(每 200ms 检查一次,避免过度触发) - 换图时直接改
<img>的src,不要动<picture></picture>结构——否则会触发重新解析,可能闪屏 - 记得预加载目标图:
const img = new Image(); img.src = 'xxx-2x.jpg';,等load后再替换 DOM 中的src
实际项目中,95% 的场景用好 <picture></picture> + srcset + sizes 就够了;所谓“无缝切换”更多是设计预期和用户感知问题——只要首屏加载正确、LCP 时间可控,人眼根本察觉不到“没切换”。硬上 JS 动态方案反而增加复杂度和内存开销,还可能因预加载失败导致空白。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











