type属性写错或缺失时浏览器直接跳过source,不发起请求;必须严格匹配标准MIME类型和codecs参数,且服务器Content-Type需一致,否则被静默忽略。

type属性写错或缺失时浏览器直接跳过source
浏览器不是“尝试加载再失败”,而是根据type值做前置判断:不匹配标准 MIME 类型,就压根不发请求。你看到 Network 面板里某个 <source> 根本没出现,不是加载慢,是被静默忽略。
常见错误包括:type="webp"(缺image/前缀)、type="image/jpg"(应为image/jpeg)、type="video/mp4"(没带codecs参数,导致 Safari 拒绝解码)。
- 服务器返回的
Content-Type响应头必须和type值完全一致,比如type="image/avif"但服务端返回text/plain,Safari 就跳过 -
type只认标准写法,不接受文件后缀推断——哪怕文件叫logo.webp,type="image/png"也会被跳过 - 旧版 Android WebView 和 iOS 13.7 之前 Safari 对
type解析更严格,多一个空格或大小写错误(如vp09写成VP09)就失效
降级链断裂的真正原因不是代码漏写,而是兜底缺失
很多人以为写了三个<source>就万事大吉,其实浏览器根本不会“选一个最接近的”。它从上到下逐条检查,第一个type支持 + 资源可解码就停;全都不满足,也不会自动 fallback 到下一个格式——而是直接放弃整个<picture>或<video>块,除非你显式提供<img src="...">或<video>里的文本内容。
所以关键不是“怎么让 source 之间互相降级”,而是确保最后一环绝对可靠:
立即学习“前端免费学习笔记(深入)”;
-
<img>必须存在,且src指向一个所有浏览器都认的格式(如jpg或png),不能是webp或avif -
<img>必须带alt,否则语义失效,SEO 和无障碍直接掉档 - 对
<video>,兜底不是靠最后一个<source>,而是<video>标签内的纯文本(如“您的浏览器不支持视频播放”)
用canPlayType()主动探测比硬写顺序更稳
光靠手写<source>顺序扛不住真实设备差异:比如 H.265 编码的 MP4 文件,type="video/mp4"声明了,但用户手机不支持 HEVC 解码,浏览器照样跳过——它不关心你文件里实际是什么编码,只看你声明的codecs是否匹配。
更可控的做法是在 JS 中提前探测:
const video = document.querySelector('video');
const canPlayAv1 = video.canPlayType('video/mp4; codecs="av01.0.05M.08"') === 'probably';
const canPlayH264 = video.canPlayType('video/mp4; codecs="avc1.42E01E"') === 'probably';
if (canPlayAv1) {
video.src = 'movie.av1.mp4';
} else if (canPlayH264) {
video.src = 'movie.h264.mp4';
} else {
// 降级到 WebM 或提示
}
注意:canPlayType()返回"probably"才代表大概率可用,"maybe"不能当作支持依据;iOS Safari 私密模式下该方法可能返回空字符串,需加兜底逻辑。
type属性不是可选项,但必须带codecs才真有用
只写type="video/mp4"等于没写:浏览器无法预判编码兼容性,会发一次请求再解码失败,浪费带宽、延迟首帧,还可能卡住播放器。真正起作用的是带codecs的完整声明。
常用组合要记准:
-
video/mp4; codecs="avc1.42E01E, mp4a.40.2"(H.264 Baseline + AAC-LC,iOS/Safari 兼容性最好) -
video/webm; codecs="vp9, opus"(Firefox/Chrome 主力,Safari 不支持) -
image/avif和image/webp不用写codecs,但type值必须一字不差
别信 FFmpeg 导出时的“-c:v libx264”参数名——最终得用ffprobe确认流信息里写的是h264还是avc1,前者在type里无效。



















