iOS Safari 音频播放需满足:双源声明且MP3在前(type="audio/mpeg")、可信用户手势触发(原生button+addEventListener)、服务端Content-Type匹配、HTTP服务运行;否则静音失败。

只写一个 MP3 源,iOS 和部分安卓 WebView 就直接静音失败——必须用 <source></source> 显式声明 type="audio/mpeg" 和 type="audio/ogg" 双源,且顺序不能反。
为什么 iOS Safari 点了按钮 still 不响
iOS Safari 要求 play() 必须在「可信用户手势」上下文中同步执行:不能是 setTimeout、不能是 Promise.then、不能绑定在没语义的 <div> 上。它只认原生 <code><button></button> 或带 role="button" tabindex="0" 的元素,且事件监听必须用 addEventListener('click', ...),play() 调用得写在回调第一行。
- 别用内联
onclick="",它不被 Safari 视为可信手势源 - 首次播放失败后,后续
play()仍可能被拒,建议用空new Audio().play().catch(() => {})在按钮点击时“唤醒”媒体上下文 - 确保按钮在视口内、未被
display: none或opacity: 0遮挡
<source></source> 的 type 写错等于没写
浏览器不会猜你文件是不是 MP3 编码,它只按 type 值匹配 MIME 类型。写成 type="audio/mp3" 或漏掉 type,Safari 和旧 Edge 就跳过该源,静默失败,连 Network 请求都不发。
- MP3 必须写
type="audio/mpeg"(不是audio/mp3) - OGG 必须是 Vorbis 编码(用
ffprobe a.ogg确认输出含Audio: vorbis),写type="audio/ogg" - 别加
<source src="a.wav" type="audio/wav"></source>作 fallback:Chrome 对 IEEE Float WAV 直接拒绝,Firefox 支持但体积大、首帧延迟高
服务端响应头不配对,前端再全也没用
即使 <source></source> 写得再规范,如果服务器返回的 Content-Type 是 text/plain 或为空,浏览器就当普通文本扔掉,根本不会调用解码器。
立即学习“前端免费学习笔记(深入)”;
- Apache 用户:在
.htaccess或虚拟主机配置中加AddType audio/mpeg .mp3和AddType audio/ogg .ogg - Nginx 用户:在
types块里补audio/mpeg mp3;和audio/ogg ogg; - 本地开发务必用 HTTP 服务(如
python3 -m http.server 8000),双击 HTML 文件走file://协议时 Chrome/Firefox 会屏蔽音频加载 - 验证方式:打开 Network 面板,确认音频请求返回 200,且 Response Headers 中
Content-Type与type完全一致
preload 和 autoplay 的真实作用被严重高估
preload="auto" 在移动端基本无效,iOS 会忽略,安卓 WebView 可能直接降级为 metadata;autoplay 加 muted 也仅对静音视频稳定,iOS Safari 把 muted 当“暂时静音”,仍要求用户先点一下才能解锁音频上下文。
- 长音频必须设
preload="metadata":只拉取时长、采样率等元数据,避免整段下载卡住首播 - 不要在
DOMContentLoaded或mounted钩子中调play(),100% 被拒 - 有声自动播放不可行,放弃幻想;静音预播后手动取消静音,必须先成功
play()一次,再改audio.muted = false
最容易被忽略的是:iOS Safari 不支持 audio/ogg,但它仍会按顺序发起每个 <source></source> 的请求。如果 OGG 放前面,它先发一次 404 或超时,再试 MP3——这不仅拖慢首播,还可能触发资源加载节流,导致后续 play() 被静默丢弃。



















