浏览器不解析文件头,只按type匹配;省略type时chrome可能碰巧播mp3,但safari(尤其ios)直接跳过source,导致duration为nan、canplay不触发、控件灰显。

HTML 本身不能做音频格式转换,所谓“兼容”是靠多源 fallback + 精确 type 声明 + 服务端配合实现的;写错一个 type 或漏配 Nginx MIME,整个链就断在 iOS Safari 上。
为什么 <source></source> 不写 type 就大概率失效
浏览器不解析文件头,只按 type 字符串调用 canPlayType() 判断是否加载。省略 type 时:
- Chrome 可能碰巧发起 MP3 请求(靠后缀猜),但纯属运气
- Safari(尤其 iOS)直接跳过该
<source></source>,不发请求、不报错、duration为NaN、canplay事件永不触发 - 多个无
type的<source></source>会依次 404,直到超时才放弃
type 值必须和实际编码严格对应
写错 MIME 或缺 codecs 参数,等于没写。常见错误:
-
audio/mp3是无效值 → 必须写audio/mpeg -
audio/ogg在 Safari 17.5+ 中被跳过 → 必须写audio/ogg; codecs="opus" -
audio/mp4不够 → 要写audio/mp4; codecs="aac",且确保文件内确实是 AAC-LC 编码(HE-AAC 或 ALAC 会返回空字符串) -
audio/wav不能写成audio/x-wav→ Safari 不认
验证方式:控制台执行 Audio.canPlayType('audio/ogg; codecs="opus"'),返回 "probably" 才算稳。
fallback 顺序不是随便排的
浏览器按 DOM 顺序逐个调用 canPlayType(),第一个返回 "probably" 或 "maybe" 的就立刻加载,后续全部忽略。错序 = 高兼容格式永不见光:
- ✅ 推荐顺序:
<source src="a.opus" type="audio/ogg; codecs=opus"></source>→<source src="a.m4a" type="audio/mp4; codecs=aac"></source>→<source src="a.mp3" type="audio/mpeg"></source>→<source src="a.wav" type="audio/wav"></source> - ❌ 别把
.wav放第一位:16-bit PCM 体积大,Firefox 虽能播,但用户得等完整下载才出声 - ❌ 别把
.mp3放最前还指望 Safari 用它:Safari 优先选mp4,但若你没提供或type写错,它不会退到 MP3
服务端配置不到位,前端写成诗也没用
Nginx/Apache 若没配对 MIME 类型、Range 请求和 CORS,Safari/iOS 直接卡 loading、拖不动进度条、currentTime 设置无效,且常静默失败:
- Nginx 必须显式声明:
add_type audio/ogg .opus;、add_type audio/mp4 .m4a;、add_type audio/mpeg .mp3;、add_type audio/wav .wav; - 响应头
Content-Type必须和<source type></source>完全一致(如audio/ogg; codecs="opus"对应Content-Type: audio/ogg,不是application/octet-stream) - 跨域音频必须带
Access-Control-Allow-Origin: *,否则 Safari 拒绝解码,连error事件都不抛 - 必须支持
Accept-Ranges: bytes,否则 iOS 无法分片加载
GitHub Pages 默认不加 CORS 头,跨域音频请求会被静默拦截——这点最容易被忽略,查控制台 Network 标签页看响应头就能确认。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











