loop属性是布尔型,仅支持loop或loop=""写法;移动端需用ended事件手动循环并判断readystate;自动播放需muted+autoplay+用户交互三者俱全。

loop 属性写法必须是布尔型,不是字符串
加了 loop 却不循环,最常见的原因是写成 loop="true" 或 loop="1"。HTML 规范里 loop 是布尔属性,只存在与否,没有值——正确写法只有 loop 或 loop=""。loop="false" 不仅无效,还会被浏览器当作“存在该属性”而触发循环。
现代浏览器(Chrome、Firefox、Safari)都遵循这一规则,但部分旧版 WebView 可能宽松解析,导致行为不一致。所以统一用 loop 最稳妥。
iOS Safari 和微信内置浏览器根本不认 loop 自动循环
哪怕写了 autoplay muted loop,iOS Safari 也会直接忽略 loop,甚至可能完全禁掉音频输出。这不是 bug,是平台强制策略:音频必须由用户手势(click、touchend)显式触发一次播放,后续的 ended 事件才能正常触发回跳逻辑。
- 首次播放必须绑定在用户可点击的元素上,比如按钮或页面任意区域的
click监听器 - 不能在
DOMContentLoaded或window.onload里调用play() - 微信内嵌浏览器还要额外检查是否启用了「同层播放」(
x5-video-player-type="h5-page"可能干扰 audio 行为)
用 JavaScript 补一层 ended 回跳才真正可控
纯靠 loop 属性,在移动端、低版本 Android、某些 MP3 文件头损坏时都容易失效。更可靠的做法是监听 ended 事件,手动重置时间并再播放:
audio.addEventListener('ended', () => {
if (audio.readyState >= audio.HAVE_FUTURE_DATA) {
audio.currentTime = 0;
audio.play().catch(e => console.warn('循环播放被阻止:', e));
}
});
注意两点:
- 一定要判断
readyState,否则在音频尚未加载完成时设置currentTime会静默失败 -
play()返回 Promise,必须用catch捕获拒绝,否则 iOS 上 silent fail 后你根本不知道循环断了
自动播放 + 静音组合必须同时满足三个条件
想实现“页面一开就静音循环”,光写 autoplay muted loop 远不够。Chrome/Firefox 要求:
-
muted和autoplay必须同时存在 - 音频元素得在
直系子节点中(不能套在<div style="display:none"> 里) <li>用户至少有一次交互(哪怕只是滚动、点击空白处),之后才能解除静音;之前即使 JS 调 <code>audio.muted = false也无效
所以真要“默认静音循环”,建议首屏放一个半透明遮罩 + 提示文字:“点击开启背景音乐”,点完再启动 audio,比硬扛策略更省事。











