audio标签必须用source多格式兜底并显式声明type,如;autoplay需绑定用户手势且配合muted;preload推荐metadata;服务器content-type必须匹配type值。

音频在老项目里经常“能播就行”,结果一换浏览器或升级系统就静音、报错、甚至整个页面卡住——这不是兼容性问题,是历史重构被跳过的典型症状。
audio 标签没写 type 属性导致 Chrome/Firefox 拒绝加载
很多旧代码只写 <source src="a.mp3"></source>,漏掉 type。现代浏览器(尤其是 Chrome 90+ 和 Firefox 88+)会直接跳过这个 <source></source>,不报错也不提示,播放器就空转。
- 必须显式声明 MIME 类型:
<source src="a.mp3" type="audio/mpeg"></source> - OGG 文件要写
type="audio/ogg",不能只靠后缀猜测 - 如果用 WebAssembly 音频解码(如 ffmpeg.wasm),
type仍需匹配原始文件格式,否则canPlayType()返回""
controls 属性缺失但 JS 手动绑定 play() 却没处理 promise 拒绝
老项目常删掉 controls,全靠 JS 控制播放。但 Chrome 66+ 起,自动播放策略收紧,play() 返回 Promise,失败时不抛异常,而是静默 reject —— 你监听不到,用户点按钮就没反应。
- 务必检查
play()的返回值:audio.play().catch(e => console.warn("Autoplay prevented:", e)) - 不要依赖
audio.paused === false判断是否真在播;要用audio.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA+audio.currentTime > 0组合验证 - 移动端 iOS Safari 还要求用户手势触发后才能首次调用
play(),否则 promise 永远 reject
src 直接写相对路径,上线后 404 却没 fallback 机制
重构时最容易忽略资源路径的上下文变化。比如开发时 src="audio/intro.mp3" 在 localhost 能播,部署到子路径(如 /app/v2/)后变成 404,error 事件又没监听,播放器就一直显示 loading 状态。
- 给
<audio></audio>绑定onerror或监听error事件,别只靠控制台看 404 - 多个
<source></source>不是“备选”,而是“按顺序尝试”;第一个 404 后浏览器不会自动试第二个,除非你手动切换src - 建议加一层路径解析逻辑:
const audioSrc = new URL("audio/intro.mp3", import.meta.url).href(ESM 环境下)
用 class 控制播放状态,但没同步更新 aria-* 属性
重构音频模块时,视觉状态(如 “playing” class)往往改了,但 aria-busy、aria-live、aria-label 这些可访问性属性还停留在初始值。屏幕阅读器读不出当前是暂停还是缓冲中,对残障用户就是黑盒。
- 每次调用
play()/pause()后,同步更新:audio.setAttribute("aria-busy", "true")、audio.setAttribute("aria-label", "正在播放:xxx") - 监听
waiting、canplay、ended等事件,动态切换aria-busy和aria-live值 - 别用
div模拟播放器控件;优先用原生<button type="button"></button>并配aria-controls指向 audio 元素 id
音频兼容不是加几个 polyfill 就完事;它卡在 DOM 生命周期、浏览器策略、资源加载链和无障碍语义四个交界点上。重构时最容易漏掉的是 error 处理链和可访问性同步,这两处一断,表面功能正常,实际已不可用。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











