浏览器不会自动降级图片格式,<picture>是唯一可控的原生方案;单个<img>只发起一次请求且不识别后缀外的格式语义,即使CDN动态返回AVIF,不支持的Safari仍会因406或损坏数据白屏。

浏览器不会自动降级图片格式,<picture> 是唯一可控的原生方案,但必须写对 <source> 顺序、type 和 fallback <img>。
为什么只写 <img src="x.jpg"> 无法实现 WebP/AVIF 降级
单个 <img> 标签只发起一次请求,浏览器不识别后缀以外的格式语义。哪怕你把 photo.jpg 配置成 CDN 动态返回 AVIF,不支持 AVIF 的 Safari 仍会收到 HTTP 406 或损坏二进制流,直接白屏或报错 Failed to load resource。
常见错误包括:
- 用
onerror内联脚本尝试切换:<img onerror="this.src='fallback.jpg'">—— 错误发生时 DOM 已渲染失败,且无法复用逻辑 - 依赖服务器 User-Agent 判断并重写响应头 —— CDN 或反向代理层不一致,移动端 WebView 行为不可控
- 把 AVIF 路径硬塞进
srcset却不声明type—— 浏览器当普通 URL 处理,不校验 MIME,加载失败无提示
<picture> 中 <source> 的 type 和 media 必须同时生效
浏览器按从上到下顺序匹配第一个满足 media 且支持 type 的 <source>。缺一不可。
立即学习“前端免费学习笔记(深入)”;
正确写法要点:
-
<source>必须带type="image/avif";Safari 16.4+ 才认这个值,旧版直接跳过整条 -
media必须是合法 CSS 媒体查询,例如(min-width: 768px),不能漏括号或写成min-width: 768px - 顺序要“现代优先”:AVIF → WebP → JPG,否则不支持 AVIF 的设备可能卡在第一条就停止匹配
- 所有
<source>必须在<img>之前,否则被忽略
示例:
<picture> <source media="(min-width: 1024px)" type="image/avif" srcset="hero-1024.avif 1x, hero-1024@2x.avif 2x"> <source media="(min-width: 768px)" type="image/webp" srcset="hero-768.webp 1x, hero-768@2x.webp 2x"> <source type="image/webp" srcset="hero-small.webp 1x, hero-small@2x.webp 2x"> <img src="hero-small.jpg" alt="hero"> </picture>
服务端 MIME 类型配置是隐性前提
就算 HTML 写对了 type="image/avif",如果 Nginx/Apache 没配 types { image/avif avif; },返回的响应头仍是 Content-Type: text/plain 或 application/octet-stream,浏览器拒绝解析,静默 fallback 到 <img>。
验证方式:
- Chrome DevTools → Network → 点开 AVIF 请求 → 查看 Response Headers 中的
Content-Type - 本地测试可用
curl -I https://yoursite.com/photo.avif直接看 header - 没配对时,控制台通常不报错,但
document.querySelector('source[type="image/avif"]').srcset对应资源永远不加载
error 事件只能兜底,不能替代 <picture> 结构
全局监听 error 适合处理路径错误或临时 404,但无法解决格式不兼容问题——因为 AVIF 加载失败时,<source> 根本没触发 error(它不是 <img>),只有最终 <img> 会抛事件。
实用做法:
- 开发阶段快速定位坏图:
Array.from(document.images).filter(i => i.naturalWidth === 0) - 仅对
<img>绑定降级:img.addEventListener('error', e => e.target.src = '/assets/placeholder.svg') - 别在
<source>上绑error—— 它没有该事件
最易被忽略的是:<img> 的 src 必须指向真实可访问的 JPG/PNG,不能是空值或占位符路径(如 data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==),否则 fallback 失效时整个区域空白。



















