现代浏览器中audio标签需同时满足多格式source兜底、正确MIME类型配置及用户交互触发三条件才能可靠播放;仅写src和controls大概率失败。

现代浏览器里,audio 标签光写 src 和 controls 就想播响,基本等于没设——90% 的播放失败不是代码漏了什么,而是格式 fallback、MIME 类型、用户交互时机这三块没对齐。
必须用 source 多格式兜底,且顺序不能错
只写一个 <audio src="a.mp3">,Firefox 可能跳过、Safari 可能静音、iOS Safari 甚至不触发 canplay 事件,控制台还一声不吭。
-
source至少配两组:<source src="a.mp3" type="audio/mpeg">(不是audio/mp3) +<source src="a.ogg" type="audio/ogg"> - MP3 放第一位:兼容性最广,解码最快;OGG 次之;WAV 仅作极短提示音兜底,别放前面——体积大、加载慢、Chrome 对 IEEE Float 编码的 WAV 直接拒解
- 别信
canPlayType()返回"probably"就真能播,它只是推测;静态 fallback 才可靠
每个 source 必须带正确 type,且服务器要配对 MIME
省略 type 或写错(比如 type="audio/mp3"),Safari 会直接跳过该 source,连请求都不发;即使请求发出去了,如果响应头 Content-Type 是 text/plain 或空着,浏览器就当普通文本扔掉。
- MP3 对应
type="audio/mpeg",OGG 对应type="audio/ogg",WAV 对应type="audio/wav" - Apache 用户加:
AddType audio/mpeg .mp3、AddType audio/ogg .ogg - Nginx 用户在
types块里补:audio/mpeg mp3;、audio/ogg ogg; - 本地开发别双击 HTML 文件——
file://协议下 Chrome/Firefox 禁音频加载,必须起本地服务:python3 -m http.server 8000
autoplay 不是“写了就播”,而是策略校验开关
写了 autoplay 却没声音?不是 JS 错了,是浏览器在等你“动手”。现代浏览器(含微信 iOS)要求:首次播放必须由可信用户手势触发,否则 play() 返回被 reject 的 Promise,报错 The play() request was interrupted。
立即学习“前端免费学习笔记(深入)”;
- 静音自动播的前提是同时写
autoplay muted,单写autoplay或只设volume=0都无效 - iOS Safari 更狠:即使
muted写了,也得用户先点一下页面,后续play()才可能恢复有声;而且元素必须在视口内、不能被display: none或opacity: 0遮挡 - 别在
DOMContentLoaded或window.onload里调play(),100% 失败;绑定到按钮点击更稳:button.addEventListener('click', () => audio.play().catch(e => {}))
JS 播放必须捕获拒绝,且多实例需分别预激活
调用 play() 不等于一定能响,Promise 被 reject 是常态,不 catch 就看不到原因。iOS 还会对每个 audio 实例单独校验用户手势上下文,播了一个不代表其他都能播。
- 必须用
audio.play().catch(e => { /* e.name 可能是 NotAllowedError / NotSupportedError / AbortError */ }) - 监听
error事件查具体哪个 source 失败:audio.addEventListener('error', () => console.log(audio.error?.code)),code === 4表示所有 source 均不可用 - iOS 上多个音频元素,得分别执行一次
play().then(() => pause())来“预激活”,不能只播一个就认为全通了
真正容易被忽略的,是服务器 MIME 类型和 iOS 对每个 audio 实例的独立手势校验——这两处出问题,连 Network 面板都看不出异常,只会沉默失败。



















