单 src 属性在 Safari 和旧 Android 上大概率失败,因浏览器不解析文件内容而只依赖 type MIME 类型匹配;省略 type 时 Safari 直接跳过加载,导致无源可播、canplay 不触发、duration 为 NaN。

只写 <audio src="a.mp3"> 就上线,90% 的用户会听不到声音——不是代码错了,是浏览器根本没加载成功。
为什么单 src 属性在 Safari 和旧 Android 上大概率失败
浏览器不会“猜”你给的 MP3 文件是否含 H.264 编码,也不会主动解包判断音频是否带 AAC 封装。它只按 type 值做 MIME 类型匹配。省略 type 时,Chrome 可能碰巧加载成功,但 Safari(尤其 iOS)会直接跳过该 <source>,导致无源可播、canplay 不触发、duration 为 NaN。
-
<source src="talk.mp3">→ iOS Safari 拒绝加载,控制台静默失败 - 多个
<source>但没写type→ 浏览器逐个发起 404 请求,直到超时 - 服务器返回
Content-Type: text/plain→ 浏览器当普通文本扔掉,连解码器都不调用
多格式 fallback 的正确写法与顺序
浏览器按 DOM 顺序尝试 <source>,遇到第一个能解码的就停止。顺序错了,Safari 会跳过最稳的格式。
- 优先放
<source src="song.m4a" type="audio/mp4">:Safari/iOS 原生首选 AAC 编码,不是看后缀,而是看实际 codec(用ffprobe song.m4a确认codec_name=aac) - 第二放
<source src="song.mp3" type="audio/mpeg">:注意是audio/mpeg,不是audio/mp3 - 第三放
<source src="song.ogg" type="audio/ogg">:确保是 Vorbis 编码(ffprobe输出含Audio: vorbis),Opus 不被 Safari 支持 - 别把
.wav当兜底:文件体积大、Chrome 对 IEEE Float 编码直接拒绝、Firefox 虽支持但加载慢
autoplay 失效不是 bug,是策略强制拦截
写了 autoplay muted 还没声音?不是 JS 写错了,是浏览器在等用户“动手”。现代浏览器(含微信 iOS)要求首次播放必须由用户手势触发,否则 play() 返回被 reject 的 Promise,控制台报 The play() request was interrupted。
立即学习“前端免费学习笔记(深入)”;
- 删掉
autoplay属性,改用按钮点击触发:document.querySelector('button').addEventListener('click', () => audio.play().catch(e => {})) - 不要在
DOMContentLoaded或window.onload里调play(),100% 失败 - iOS Safari 更严格:元素必须在视口内、未被
display: none或opacity: 0遮挡 - 想静音自动播?
muted+autoplay在多数桌面浏览器可行;想有声自动播?只能等用户第一次交互后再调一次play()
JS 播放必须捕获错误并监控状态链
用户点一下 play() 不等于一定能响,必须监听拒绝和加载错误,不能只靠 canplay 判断就绪。
- 用
audio.play().catch(e => { })捕获NotAllowedError(自动播放被拒)、NotSupportedError(格式不支持)、AbortError(网络中断) - 监听
error事件可发现具体哪个<source>失败:audio.addEventListener('error', () => console.log(audio.error?.code)),code === 4表示所有<source>均不可用 - 不要依赖
canplay—— 它在元数据加载完就触发,音频体可能还没到;canplaythrough更可靠,但移动端常不触发,建议降级监听loadeddata+networkState === 1 - 本地开发别双击 HTML 文件跑 ——
file://协议下 Chrome/Firefox 直接屏蔽音频加载,用python3 -m http.server 8000启服务
真正难的不是写几行 <source>,而是每个环节都得对齐:服务器 MIME 类型、音频编码实测结果、iOS 手势上下文、错误路径全覆盖。漏掉任意一环,用户听到的就是沉默。



















