<source>标签顺序决定播放优先级,浏览器按DOM顺序调用canPlayType(),返回"probably"或"maybe"即加载并停止尝试;Safari 17.5+不支持audio/ogg但认audio/ogg; codecs="opus",Chrome优先解码Opus;推荐顺序:opus→m4a→mp3,type属性须精确到编码,服务端Content-Type必须严格匹配,Nginx需显式配置MIME类型,preload="metadata"最稳妥,JS播放需分别捕获NotAllowedError、NotSupportedError、AbortError三类错误。

source 标签顺序决定谁能播,不是写了就有效
浏览器按 <source> 的 DOM 顺序逐个调用 Audio.canPlayType(),只要返回 "probably" 或 "maybe" 就立刻加载并停止尝试后续。Safari 17.5+ 完全不认 audio/ogg(哪怕后缀是 .ogg),但对 audio/ogg; codecs="opus" 返回 "probably";Chrome 则优先解码 Opus,放第一位能省带宽、减少首帧延迟。
常见错误:把 .wav 放第一位——16-bit PCM 文件体积大,Firefox 虽支持,但用户得等完整下载才出声;或漏掉 type 属性,导致浏览器跳过 MIME 检查直接试播,失败时只报 MEDIA_ERR_DECODE,根本看不出是哪个 source 挂了。
- 推荐 fallback 顺序:
<source src="a.opus" type="audio/ogg; codecs="opus"">→<source src="a.m4a" type="audio/mp4; codecs="aac"">→<source src="a.mp3" type="audio/mpeg"> - 删掉没写
type的<source>,它只会增加不可控的试探性请求 - 验证是否真支持:控制台执行
Audio.canPlayType('audio/ogg; codecs="opus"'),返回"probably"才算稳
type 属性必须精确到编码,不能只写大类
type="audio/ogg" 不够,浏览器可能返回空字符串;type="audio/ogg; codecs="opus"" 才能触发 Chrome/Safari 的 Opus 解码路径。同理,.m4a 必须是 AAC-LC 编码(不是 HE-AAC、不是 ALAC),可用 ffprobe a.m4a 看 codec_name 是否为 aac;MP3 必须是标准 MPEG-1 Layer 3,某些企业内网禁用 MP3 解码,只认 audio/wav 或 audio/opus。
- 服务端响应头
Content-Type必须和type值完全一致,比如audio/ogg; codecs="opus"对应Content-Type: audio/ogg,不能是application/octet-stream - Nginx 需显式配置:
add_type audio/ogg .opus;、add_type audio/mp4 .m4a;、add_type audio/mpeg .mp3; - 跨域音频必须带
Access-Control-Allow-Origin: *,否则 Safari 直接拒绝解码,连 error 事件都不抛
preload="metadata" 是平衡体验与流量的默认选择
preload="auto" 在移动端常被忽略,部分 Android WebView 会直接降级为 metadata;preload="none" 虽省流量,但用户点播放要等完整加载,首播延迟高;preload="metadata" 只取时长、采样率等元数据,不下载音频体,是桌面端和多数 WebView 下最稳妥的折中方案。
立即学习“前端免费学习笔记(深入)”;
- 不要依赖
canplay判断就绪——它在元数据加载完就触发,音频体可能还没到;canplaythrough更可靠,但会显著延迟首次播放时机 - 若需预加载关键提示音,可用
<link rel="preload" as="audio" href="beep.opus">,但注意它不触发canplay,仍需监听自身 audio 元素事件 -
preload对自动播放无帮助,现代浏览器(Chrome ≥70、Firefox ≥66、Safari ≥12.1)默认阻止有声自动播放,muted是硬性前提
JavaScript 播放必须捕获三类错误,不能只 catch 一个
用户点击后调用 audio.play() 不等于一定能响。必须用 .catch() 分别处理:NotAllowedError(自动播放被拒)、NotSupportedError(格式不支持)、AbortError(网络中断)。同时监听 error 事件看具体哪个 <source> 失败:audio.error?.code === 4 表示所有 source 均不可用。
- 不要在
loadstart或loadeddata后直接play(),它们不保证解码就绪;优先等canplaythrough,或至少canplay+networkState === 3 - 若中途 JS 修改了
src,loop状态不会重置,需手动设audio.loop = true -
muted是布尔属性,写muted即生效;设muted="false"无效,JS 中要恢复声音得用audio.muted = false



















