是唯一能可靠按设备能力选图的原生方案,必须用显式声明格式支持性,配合media和srcset实现精准降级,兜底不可省;混用格式或描述符会导致解析失败或选图错误。

用 <picture></picture> + srcset 实现分辨率降级
浏览器不支持高分辨率格式(如 AVIF、WebP)时,必须有明确的 fallback 路径,否则图片直接不显示。关键不是“降低分辨率”,而是“按设备能力选最合适的图”,<picture></picture> 是唯一能可靠控制这个逻辑的原生方案。
常见错误是只写一个 <img src="xxx.jpg">,或把 WebP 和 JPG 混在同一个 srcset 里——浏览器会忽略不支持的 MIME 类型,但不会自动切到下一个 source,除非你用 type 显式声明。
- 每个
<source></source>必须带type属性,例如type="image/avif",否则浏览器无法判断是否支持 -
media属性决定触发条件,比如media="(min-resolution: 2dppx)"可专门匹配 Retina 屏 - 兜底的
<img>标签不能省,它没type,也不受media控制,是最后的保底加载项 - 不要在
srcset中混用不同格式,如photo.webp 1x, photo.jpg 2x—— 这会导致部分浏览器解析失败或只加载第一个
srcset 里写 1x/2x 还是 w 描述符?
取决于你优先保障「设备像素密度」还是「视口宽度」。移动端适配推荐用 w 描述符,因为屏幕物理尺寸差异大,仅靠 dpr 判断容易错配;桌面端若明确区分普通屏和 Retina 屏,可用 1x/2x 更简洁。
例如 iPhone 15 Pro Max 的 dpr 是 3,但它的视口宽度只有 430px,如果只写 2x,它可能加载了本该给 2x 屏的图,结果文件过大;而用 430w + sizes,浏览器能结合实际布局宽度选最省流量的版本。
-
1x/2x适合固定宽高的容器,比如头像、图标等尺寸稳定的元素 -
w描述符必须配合sizes属性,否则浏览器按 100vw 猜测,容易选错 - 混合使用风险高:比如
photo.jpg 400w, photo@2x.jpg 2x,Chrome 会优先按w解析,Safari 可能直接忽略2x
降级时图片尺寸不一致导致布局抖动
当高分辨率图加载完成、低分辨率图被替换时,如果两张图的宽高比或 intrinsic size 不同,<img> 高度会突变,造成内容跳动。这不是样式问题,而是 HTML 渲染机制决定的:浏览器按第一张图的 naturalWidth/naturalHeight 占位,后续切换不会重排。
解决方式只有一个:所有降级选项的图片必须保持相同宽高比,且最好内联 width 和 height 属性(注意不是 CSS)。这样浏览器能在首帧就分配准确空间。
- 不要依赖 CSS 的
aspect-ratio或padding-top技巧来撑开容器——它们在图片加载前不生效 - 生成降级图时,统一裁剪/缩放至相同比例,比如全部输出为 4:3 或 16:9
- 如果原始图比例不可控(如用户上传),服务端应生成多个比例版本,前端按需选择,而非靠 CSS 强行拉伸
JS 动态切换 src 无法触发浏览器缓存复用
有人试图用 JS 监听 onerror 后改 img.src 做降级,这看似简单,但有两个硬伤:一是首次加载失败时已触发网络请求,再换地址等于多一次请求;二是新 URL 即使内容相同,浏览器也视为全新资源,不会复用已缓存的低分辨率图。
原生 <picture></picture> 的优势在于所有候选资源都在 HTML 解析阶段被预加载器识别,浏览器可并行探测支持性,并复用已下载的资源(只要 URL 相同)。
- 避免在
img.onerror里赋值src,尤其不要写成img.src = img.src.replace('.webp', '.jpg') - 如果必须用 JS 控制(如 CMS 动态拼 URL),至少提前预加载降级图:
const preloader = new Image(); preloader.src = 'fallback.jpg'; - Service Worker 可拦截请求并按 MIME 支持情况重写响应,但复杂度远高于
<picture></picture>,仅限高级场景
srcset 就算降级”,结果发现 iOS Safari 加载了 4K 图却只显示 200px 宽,或者 fallback 图被压缩得面目全非——这些都不是代码写法问题,而是资源生成链路没对齐。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











