标签必须作为或的直接子元素,按顺序尝试首个type匹配、http 200且能解码的资源;ios safari强制首源为h.264 mp4,否则静音或报错。

<source></source> 标签本身不播放、不渲染,只提供候选资源列表;浏览器按 DOM 顺序逐个尝试,首个 type 匹配 + src 返回 200 + 能实际解码的,就加载并停止——其余全部跳过。它不是“智能选最优”,而是“找到第一个能用的就停”。
为什么写在
浏览器直接抛 DOMException: The element has no supported sources,播放器区域完全空白,控制台甚至可能不报错。这不是兼容性问题,是硬性结构约束。
-
<source></source>必须是<video></video>或<audio></audio>的**直接子元素**,中间不能隔<p></p>、注释、<div> 等任何节点 <li>写在 <code>顶层、或用 JS 动态插入但没挂到父标签下,等同于没写 -
<picture></picture>场景同理:<source></source>必须嵌套在<picture></picture>内,且是其直接子元素 - MP3 文件:必须用
type="audio/mpeg",不是audio/mp3 - WebM(VP9):推荐
type="video/webm";若加codecs,注意大小写和点号,如vp09.00.10.08错写成VP9或vp09.0.10.8就失效 - AV1 MP4:必须写全
type="video/mp4; codecs="av01.0.05M.08"",只写video/mp4会被 Safari 当作 H.264 处理,解码失败 - 本地开发用
file://协议时,type完全被忽略 → 必须起 HTTP 服务,例如npx serve - 排查方法:把每个
src值粘贴到新标签页打开,看能否下载成功 - Network 面板过滤
media,检查状态码是否为 200,响应头Content-Type是否匹配type - 相对路径以当前 HTML 文件位置为基准,不是 JS/CSS 所在目录
- 确保服务器配置了正确的 MIME 类型映射,尤其 Nginx/Apache 自建服务时
- 正确顺序:H.264 MP4(带完整 codecs)→ VP9 WebM → 其他(如 AV1 MP4)
- H.264 推荐参数:
type="video/mp4; codecs="avc1.42E01E, mp4a.40.2""(Baseline Profile + AAC-LC) - 别把 WebM 放第一位——Safari 直接跳过,且不 fallback 到下一个,整个
<video></video>可能卡死 - 用
ffprobe检查真实编码,别信文件名;用curl -I确认响应头
type 属性必须和 Content-Type 响应头严格一致
浏览器不看文件后缀,只比对 type 值和服务器返回的 Content-Type 响应头。差一个字符(比如 audio/mp3 vs audio/mpeg),Safari 就可能静默跳过该源。
src 路径出错时浏览器静默失败
404、跨域、大小写不匹配(song.MP3 ≠ song.mp3)、权限拒绝……这些都不会触发控制台错误,也不会显示 fallback 文字。你只会看到空控件或 loading 卡住。
iOS Safari 对第一个有硬性编码要求
它强制要求第一个可解码的 <source></source> 必须是 H.264 编码的 MP4,否则可能静音、禁止自动播放,甚至抛 NotAllowedError。这不是 bug,是 WebKit 的行为规范。
真正容易被忽略的,是 type 和响应头的精确匹配,以及 iOS 对首个 <source></source> 的编码强制要求——这两点不达标,再多备选也无效。











