type属性不带codecs等于没写,浏览器仅校验mime类型而无法预判编码兼容性,导致请求发出后解码失败、黑屏且无报错;真正生效的是完整声明如type="video/mp4; codecs="avc1.42e01e, mp4a.40.2"",实现请求前双层校验。

type属性不带codecs等于没写
只写 type="video/mp4" 时,浏览器只能确认 MIME 类型,无法预判内部编码是否能解码。结果是:请求照发,下载完成才发现播不了——Network 面板显示 200,但视频黑屏、无报错、error 事件也不触发。这本质上是把校验延迟到了解码阶段,失去了 <source></source> 的“提前过滤”价值。
真正起作用的是带 codecs 参数的完整声明,比如:type="video/mp4; codecs="avc1.42E01E, mp4a.40.2""。它让浏览器在发起网络请求前,就完成“MIME 类型 + 编解码器”的双层校验。不匹配的 <source></source> 直接被跳过,连 HTTP 请求都不会发出。
- 写错 codecs 值(如
h264或avc1.640033但文件实际是 High Profile)→ Safari 静默忽略整条 source - 空格、逗号、引号位置不一致 → 与服务器返回的
Content-Type响应头逐字符比对失败 → 不匹配 - 用
ffprobe -v quiet -show_entries stream=codec_name,profile -of csv video.mp4确认真实编码,别信后缀或导出设置
iOS Safari 强制首个 source 必须是 H.264 + AAC
WebKit 内核(包括 iOS Safari 和所有 WebView)不会 fallback。如果第一个 <source></source> 不是 H.264 Baseline/Main Profile + AAC-LC 编码的 MP4,且 type 声明不精确匹配,整个 <video></video> 就会被判定为不可用:静音、自动播放被禁、甚至抛 NotAllowedError。后续所有 <source></source> 全部失效,Network 面板里一个请求都看不到。
- 必须放第一位:
<source src="vid-h264.mp4" type="video/mp4; codecs=" avc1.42e01e mp4a.40.2></source> - 导出时加 FFmpeg 参数:
-profile:v baseline -level 3.0 -c:a aac -b:a 128k - 服务器响应头
Content-Type必须和type属性值完全一致(含空格、逗号、引号),差一个字符就失败 - 别把
<source src="vid.webm" type="video/webm"></source>放第一位——真机上大概率白屏
浏览器选 source 的真实逻辑不是“谁排第一就用谁”
浏览器按 DOM 顺序遍历每个 <source></source>,对每一条执行两步判断:① type 是否被支持;② 实际文件是否可解码(需结合设备能力)。只有两者都满足,才选用该 source。所以即使你把 AV1 MP4 放最前,但用户用的是旧版 Safari,它会直接跳过,继续往下找 H.264 MP4 或 VP9 WebM。
- 推荐顺序:
webm(VP9/AV1)→mp4(H.264)→ogg(Theora),兼顾现代性与降级能力 -
media属性(如media="(min-width: 768px)")基本被所有浏览器忽略,它不控制解码行为,仅影响是否预加载 - 不要依赖
canPlayType()返回"probably"就认为一定能播——它只查本地能力,不验证远程文件实际编码 - 动态替换
<source></source>后,必须显式调用video.load(),否则仍播旧缓冲
本地开发时 type 匹配完全失效
用 file:// 协议打开 HTML 时,浏览器会跳过所有 type 校验逻辑,直接尝试加载第一个 src。这意味着你在本地测通了,上线后 iOS Safari 可能立刻白屏。必须用 http:// 或 https:// 服务测试,哪怕只是 npx http-server 起个本地服务。
- 用
curl -I https://your.domain/vid.mp4检查响应头是否真为Content-Type: video/mp4; codecs="avc1.42E01E, mp4a.40.2" -
<video></video>不能同时写src属性和<source></source>子元素——两者互斥,写了src会忽略全部<source></source> - 所有
<source></source>必须是<video></video>的直接子元素,嵌套在<div> 里会导致 <code>DOMException: The element has no supported sources - 路径大小写、跨域、404 都不会报错,只会静默跳过——逐个在新标签页打开
src链接验证可访问性
实际生效的关键不在“写了多少种格式”,而在于第一个
<source></source> 的 type 和真实编码是否严丝合缝——差一个空格,iOS 就拒绝解码,且控制台不提示原因。











