不能只靠 audio.volume,因其无插值能力、ios易被静音、时机难控、线性变化不符合人耳对数感知;应使用web audio api的gainnode配合settargetattime实现指数曲线淡入淡出。

直接用 <audio></audio> 标签的 volume 属性无法实现真正平滑的淡入淡出——它没有内置过渡能力,手动定时修改容易卡顿、在 iOS Safari 上常被静音策略拦截,且精度低、易爆音。要达到网页背景音乐所需的无缝、自然、跨设备稳定的淡入淡出效果,必须借助 Web Audio API。
为什么不能只靠 audio.volume
HTML5 <audio></audio> 的 volume 是一个简单数值属性(0.0–1.0),浏览器不为其提供插值或缓动支持。即使配合 requestAnimationFrame 线性更新,也会出现以下问题:
- 移动端(尤其 iOS Safari)在非用户手势后设置
volume可能被忽略或强制归零 - 音频未进入
canplay状态前修改 volume 无效,时机难把控 - 线性变化不符合人耳对响度的对数感知,听感前段“没动静”、后段“突然变响”
- 无法与音频播放时序精确对齐(如
context.currentTime),跳转或暂停时易失控
正确做法:用 AudioContext + GainNode 接管音频输出
把 <audio></audio> 当作原始声源,用 Web Audio API 构建一条可控音频通路:
- 用户点击/触摸等手势触发时,创建
AudioContext(避免被挂起) - 调用
context.createMediaElementSource(audioEl)将 audio 元素接入音频图 - 插入一个
GainNode,所有音量控制都通过它完成 - 连接路径为:
mediaSource → gainNode → context.destination
用 setTargetAtTime 实现自然淡入淡出
GainNode.gain.setTargetAtTime() 按指数曲线逼近目标值,听感柔和、无跳变,是背景音乐切换的首选:
- 淡入:先设
gainNode.gain.setValueAtTime(0, context.currentTime),再调gainNode.gain.setTargetAtTime(1, context.currentTime, 0.15)(0.15 秒时间常数,约 450ms 达到 0.99) - 淡出:调
gainNode.gain.setTargetAtTime(0, context.currentTime, 0.15),然后在延迟约0.15 * 3 ≈ 450ms后调audio.pause()并断开节点连接 - 避免资源泄漏:淡出完成后执行
gainNode.disconnect(),并清空引用
多背景音乐交叉淡入淡出的关键点
若需轮播多首背景音乐(如“上一首渐弱、下一首渐强”),必须为每首独立配置 GainNode:
- 不要共用同一个 GainNode,否则音量会叠加或相互干扰
- 新音乐淡入前,确保其 GainNode 增益从 0 开始;旧音乐淡出时,其 GainNode 单独设目标为 0
- 两路操作使用同一
context.currentTime作为起始时间,保证同步 - 可封装成
fadeTo(nextAudio, duration = 2000)函数,自动管理当前/目标节点状态
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











