audio标签兼容播放需<source>多格式+显式type声明+fallback文本;单src或漏type会导致Firefox等因解码器缺失静默失败;autoplay muted仍可能被iOS/Android策略拦截,须用户手势后调用play()并捕获Promise拒绝。

audio 标签本身不保证兼容播放,真正起作用的是多格式 source + 显式 type 声明 + 合理 fallback 文本。只写一个 src 或漏掉 type,Chrome 可能播,Firefox 就直接静音失败。
为什么单写 src 会导致部分浏览器无法播放
浏览器对音频解码器的支持是硬性限制:Safari 和 Chrome 原生支持 audio/mpeg(MP3),但不支持 audio/ogg;Firefox 和旧版 Edge 则相反。如果只用 <audio src="song.mp3"></audio>,Firefox 会尝试加载 MP3,但因缺少解码器而触发 error 事件且不报错提示——页面看起来“没反应”。
解决方法必须显式提供至少两种格式,并标注 type:
<audio controls> <source src="song.mp3" type="audio/mpeg"> <source src="song.ogg" type="audio/ogg"> 您的浏览器不支持音频播放,请下载:<a href="song.mp3">MP3</a> </audio>
-
type属性不是可选的——它让浏览器跳过实际加载就能判断是否支持,避免白忙一场 - 顺序很重要:
<source>从上到下匹配,第一个type被支持的就加载,后面的被忽略 - MP3 放第一位,覆盖最广;OGG 放第二位,兜底 Firefox / Linux 浏览器
autoplay 加 muted 也不一定生效的三个原因
即使写了 autoplay muted,iOS Safari、部分 Android WebView、以及 Chrome 的隐身窗口仍可能拒绝播放。这不是 bug,而是策略强制。
立即学习“前端免费学习笔记(深入)”;
- 移动端 iOS 必须由用户手势(如
click、touchend)触发play(),autoplay完全无效 - Chrome 在用户未与页面交互前,会把
autoplay当作“静默失败”,不抛错也不警告 -
muted只绕过“有声自动播放拦截”,但若音频文件损坏、路径 404 或 CORS 阻止加载,play()仍会 Promise reject
稳妥做法是监听用户首次点击后手动调用:
let audio = document.querySelector('audio');
document.body.addEventListener('click', () => {
audio.play().catch(e => console.warn('自动播放被阻止:', e));
}, { once: true });
如何检测音频是否真的加载成功并可播放
仅靠 canplay 或 loadeddata 事件不够——它们在元数据加载完就触发,不代表音频能解码或网络通畅。真实可用的判断点是 canplaythrough,但它可能永远不触发(如带宽不足)。
- 优先监听
error事件,检查audio.error.code:MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED表示格式不支持,MEDIA_ERR_NETWORK是加载失败 - 用
audio.readyState辅助判断:值为4(HAVE_ENOUGH_DATA)才表示可连续播放 - 对关键场景(如语音反馈),别等事件,直接在
play()的 Promise catch 中降级处理
例如:
audio.play().catch(() => {
// 自动播放失败,显示“点击播放”按钮
document.getElementById('play-btn').style.display = 'block';
});
最容易被忽略的是:即使所有 <source> 都声明了 type,如果服务器返回的 HTTP Content-Type 头和 type 不一致(比如 .mp3 文件被服务器设成 text/plain),Chrome 会直接拒绝加载——这时连 error 事件都不触发,只能靠 Network 面板查响应头。



















