audio标签播不了主因是未做兼容性测试,需用canplaytype()实测格式支持、network面板查mime类型、ios需用户手势+preload="metadata"、监听error和promise reject,静态多格式fallback才可靠。

audio 标签写完就播不了?不是代码漏了 controls,也不是路径错了——90% 是没做兼容性测试,直接拿单个 MP3 上线。
用 canPlayType() 实测格式支持,别信 Modernizr
Modernizr 只告诉你浏览器认不认识 audio 标签,不告诉你能不能解码 MP3。真正能播的格式,必须自己调 canPlayType() 验证:
- 创建临时元素:
const a = document.createElement('audio') - 挨个试:
a.canPlayType('audio/mpeg')、a.canPlayType('audio/ogg')、a.canPlayType('audio/wav') - 结果只有
''(空字符串)、'maybe'、'probably'三种;只把返回'probably'的格式放进<source></source> - Firefox 对
audio/mpeg常返回'maybe',但实际能播,所以别只依赖这个值;MP3 + OGG 组合仍是桌面端最稳兜底
Network 面板里看 Content-Type,不是看控制台有没有报错
浏览器静默失败时控制台往往一片空白。真问题藏在 Network 面板里:
- 点开音频请求,确认状态码是
200,不是404或304 - 检查响应头
Content-Type:MP3 必须是audio/mpeg,不是audio/mp3或application/octet-stream - 本地开发别双击 HTML ——
file://协议下 Chrome 直接屏蔽加载,必须起服务:python3 -m http.server 8000 - Apache 用户加
AddType audio/mpeg .mp3到.htaccess;Nginx 补audio/mpeg mp3;到types块
iOS Safari 播放失败,先查 preload 和用户手势上下文
iOS WebKit 不按常理出牌:哪怕你写了 autoplay muted,只要没满足“用户已交互+元素在视口内+preload 设对”,照样静音。
-
preload必须设为metadata,auto在 iOS 上被忽略,且可能触发预加载阻塞 -
play()调用必须包裹在真实用户事件里,比如button.addEventListener('click', () => audio.play()) - 不能在
DOMContentLoaded、load、甚至canplay里调play()—— iOS 不认这些为“用户触发” - 元素不能被
display: none、opacity: 0或transform: scale(0)遮挡,否则即使点了按钮也无效
监听 error 和 Promise reject,别只等 canplaythrough
canplaythrough 看起来可靠,但它等的是“预计能播完”,会显著延迟首次播放时机,且不反映格式是否真被支持。
- 监听
error事件:audio.addEventListener('error', () => console.log(audio.error?.code)),code === 4就是所有<source></source>全军覆没 -
play()返回 Promise,必须catch:audio.play().catch(e => { if (e.name === 'NotAllowedError') {...} }) - 不要用
canPlayType()结果动态插入<source></source>—— DOM 插入后浏览器不会重新扫描,fallback 机制失效,静态声明才是唯一可靠方式
兼容性测试不是一次性的 checklist,而是每次改 src、换编码、切服务器配置后都得重跑的闭环:Network 看 MIME → canPlayType 实测 → iOS 真机点按验证 → error/catch 捕获日志。漏掉任一环,上线后静音就是默认行为。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











