多个source标签用于同一音频的格式兜底,非实现多音频切换;必须按浏览器支持优先级顺序排列(如mp3→ogg→wav),且每个source需正确声明type属性,否则回退失效。

audio 标签里用多个 <source></source> 实现格式回退
浏览器对音频格式的支持不一致,单写一个 src="music.mp3" 在 Firefox 或旧版 Safari 上会直接空白——不是代码错了,是它根本没尝试加载。必须用 <source></source> 子标签按顺序提供多种格式,浏览器遇到第一个「支持 + 可访问」的就停。
推荐组合:<source src="music.mp3" type="audio/mpeg"></source> 放最前(兼容性最广),<source src="music.ogg" type="audio/ogg"></source> 次之(压缩率高、开源、Chrome/Firefox/Edge 全支持),<source src="music.wav" type="audio/wav"></source> 最后(仅用于极短提示音,体积大)。
-
.mp3不是万能的:Safari 支持好,但 Firefox 从不支持 MP3 解码(除非系统级解码器介入,不可靠) -
.ogg文件实际多为 Vorbis 编码,不是所有叫.ogg的文件都可用;用ffprobe your-file.ogg确认是Audio: vorbis而非opus或封装错误 - 不要依赖
type属性做“智能匹配”:浏览器只看type是否在canPlayType()返回值中,不校验文件真实编码;写错type="audio/ogg"却放了个 AAC 封装的 MP4,照样失败
为什么写了多个 <source></source> 还是播不了
常见假象是“写了备用路径,但只有第一个生效”,其实问题常出在路径或服务器响应上。浏览器不会跳过第一个去试第二个,除非第一个明确返回 404 或 Content-Type 错误。
- 检查 Network 面板里音频请求的状态码:如果是
net::ERR_FILE_NOT_FOUND或请求压根没发出,说明路径无效或协议被拦截(file://下必挂) - 点开音频请求的 Headers,确认
Content-Type是audio/mpeg(MP3)、audio/ogg(OGG)等,不是text/plain或空——很多本地 HTTP 服务(如 Pythonhttp.server)默认不配 MIME 类型 - Apache 用户加
AddType audio/mpeg .mp3到.htaccess;Nginx 用户在types块补audio/mpeg mp3;
路径写法影响 <source></source> 是否被识别
<source></source> 的 src 是相对 URL,基准永远是 HTML 文件所在目录,跟它写在 <table> 里还是 <code><div> 里无关。但嵌套深了容易误判层级。<p><span>立即学习</span>“<a href="https://pan.quark.cn/s/cb6835dc7db1" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">前端免费学习笔记(深入)</a>”;</p>
<ul>
<li>避免用 <code>../ 向上跳:比如 HTML 在 /pages/story.html,音频在 /assets/audio/ch1.mp3,别写 src="../../assets/audio/ch1.mp3",统一用根路径 src="/assets/audio/ch1.mp3"
src="背景音乐.mp3" 在 Safari 和部分 Chrome 版本会静默失败<source src="%60/audio/%24%7Bname%7D.mp3%60"></source> 这种写法极易断裂autoplay + muted 仍被拒绝?那不是格式问题,是策略问题
写了 <source></source> 备用路径,也确认了 MIME 类型和路径,但 autoplay 仍不触发,这不是兼容性问题,是浏览器的自动播放策略升级了。
- Chrome 94+ 要求:页面必须有用户交互(如点击、触摸)后,才能调用
play();即使加了muted,首次无交互时play()也会抛DOMException - iOS Safari 更狠:完全禁用
autoplay,且不触发 Promise,audio.play().catch(e => console.log(e))里连错误都收不到 - 解决方案不是换格式,而是改逻辑:用按钮触发播放,或监听
click后再调用play(),别依赖纯属性驱动
.ogg 和 .mp3 顺序,却忽略服务器返回的是 text/plain,或者本地双击 HTML 导致整个 <source></source> 链路被 file:// 协议拦死。



















