必须用多格式兜底,提供MP3+OGG双源并显式声明type为audio/mpeg和audio/ogg;服务端需返回正确Content-Type;autoplay需用户手势触发;iOS与Android事件时机不同需分平台处理。

必须用多格式兜底,不能只写src
只写 <audio src="a.mp3"></audio> 在 Safari(尤其 iOS)、Firefox、旧版 Android WebView 上大概率静默失败——浏览器不解析文件头,只按 type 做 MIME 匹配。没 type 就跳过,不报错也不加载。
正确做法是至少提供 MP3 + OGG 两组源,并显式声明 type:
<audio controls> <source src="a.mp3" type="audio/mpeg"> <source src="a.ogg" type="audio/ogg"> 您的浏览器不支持 audio 标签。 </audio>
-
type="audio/mp3"是错的,必须是audio/mpeg - Ogg 文件建议用 Vorbis 编码(不是 Opus),可用
ffprobe a.ogg确认 - 别加
.wav作 fallback:Chrome 对 IEEE Float 编码的 WAV 直接拒绝
服务器必须返回正确的 Content-Type 响应头
即使 HTML 写对了,如果服务端返回的响应头里 Content-Type 是 text/plain 或空着,浏览器会当普通文本处理,音频根本不会进解码器。
常见本地开发陷阱:双击打开 HTML 文件走 file:// 协议,Chrome/Firefox 会直接屏蔽音频加载——必须用本地服务(如 python3 -m http.server)。
立即学习“前端免费学习笔记(深入)”;
- Apache:在
.htaccess加AddType audio/mpeg .mp3和AddType audio/ogg .ogg - Nginx:在
types块中补audio/mpeg mp3;和audio/ogg ogg; - 开发时打开 Network 面板,确认音频请求的 Status 是 200,且 Response Headers 含正确
Content-Type
autoplay 不是属性问题,而是用户手势+静音策略问题
写了 autoplay muted 还不响?不是代码漏了,是浏览器在等用户“点一下”。Chrome、Safari、Firefox 全部要求首次播放必须由真实用户交互触发(click/touch),否则 play() 返回被 reject 的 Promise,控制台报 The play() request was interrupted。
真正能落地的自动播放逻辑是:
- 删掉 HTML 中的
autoplay属性 - 用按钮绑定 click:
document.querySelector('button').addEventListener('click', () => audio.play().catch(e => {})) - iOS Safari 更严:元素必须在视口内、未被
display: none或opacity: 0遮挡 - 若需后续有声播放,可先用
muted = true播一次,再设muted = false
iOS 和 Android 的事件与设置时机差异必须区分处理
在 iOS WebKit 上,currentTime 必须等 canplay 事件后才能设;Android(尤其低版本 WebView)压根不触发 canplay,但 play 事件相对可靠。混用会导致 iOS 设置无效、Android 卡加载。
判断平台后分路径处理最稳:
- iOS:监听
canplay,再设currentTime并调play() - Android:直接设
currentTime,然后调play() - 监听播放完成别只靠
ended:iOSended常延迟或不触发,改用timeupdate判断currentTime >= duration
兼容性不是“写对标签就完事”,而是格式、服务端、JS 行为、平台策略四层全对齐。漏一层,iOS 上就静默,Android 上就卡住,用户感知就是“音频坏了”。



















