用 analysernode 的 getbytefrequencydata() 获取实时频率数据,需设置 fftsize(如256)、创建 uint8array 缓冲区、在 requestanimationframe 中循环读取,并注意移动端需用户手势触发;再通过 css 自定义属性 --freq-0 至 --freq-127 绑定频段值,配合 transition 实现平滑柱状图动画。

怎么用 AudioContext 获取实时频率数据
浏览器里拿不到原始音频波形或频谱,得靠 AnalyserNode 做 FFT 运算。关键不是“播放音频”,而是把音频源(MediaElementAudioSourceNode 或 AudioBufferSourceNode)连到分析节点上,再用 getByteFrequencyData() 拿到 0–255 的归一化频段值。
常见错误是漏掉 analyser.fftSize = 256(或 512/1024),默认值太小导致频段过少;还有忘记调用 requestAnimationFrame 循环读取,数据就停在第一帧。
-
fftSize必须是 2 的幂,推荐 256(128 个频段)起步,太大影响性能 - 调用
getByteFrequencyData()前必须先创建Uint8Array缓冲区,长度为analyser.frequencyBinCount - 移动端需在用户手势(如点击)后才能启动
AudioContext,否则静音
怎么把 JS 频率数组转成 CSS 变量
CSS 本身不支持数组,但可以用多个自定义属性模拟,比如 --freq-0 到 --freq-127。每次更新时遍历频率数组,用 element.style.setProperty() 批量写入——别用 style.cssText,会覆盖已有内联样式。
注意变量名要合法:不能含小数点、不能纯数字开头,所以索引建议用 0 而非 0.0;另外变量值必须是字符串,String(freq[i]) 比模板字面量更稳妥。
- 只更新变化的频段(加个阈值判断),避免无意义重绘
- 如果元素多(比如 100 个柱子),改父容器的
:root变量比逐个元素设更高效 - 变量值单位无关(CSS 不校验),但建议统一用无单位数字,方便
scaleY()或height直接用
怎么用 CSS 变量驱动频谱柱状图动画
核心是把每个柱子的高度或缩放绑定到对应变量,比如 height: calc(var(--freq-0) * 1px); 或 transform: scaleY(calc(var(--freq-0) / 255));。别用 animation,那是固定曲线;要用 transition: height 0.05s linear; 让每次 JS 更新都平滑过渡。
容易踩的坑:Chrome 对 calc() 中变量未定义时行为不一致(有时 fallback 为 0,有时报错),务必初始化所有变量(如 :root { --freq-0: 0; --freq-1: 0; ... })。
-
transition时间设太长(>0.1s)会拖慢响应,太短( - 用
will-change: transform;提升柱子层,避免每帧重排 - 如果用
clip-path做波形线而非柱子,变量得转成polygon()字符串,此时 JS 拼接更可控
为什么频谱看起来“迟钝”或“抖动”
不是代码错了,是信号处理链路里的延迟叠加:音频解码缓冲、FFT 计算耗时、JS 执行间隙、CSS 渲染管线排队。单靠提高刷新率没用,得从源头压延迟。
- 减小
analyser.smoothingTimeConstant(默认 0.8),设为 0.1–0.3,让响应更快(代价是噪点变多) - 用
setTimeout+performance.now()替代requestAnimationFrame,可绕过渲染帧率限制(但慎用,易卡主线程) - 避开
console.log和大数组slice(),高频循环里任何非必要操作都会累积延迟 - 真要低延迟,得用 WebAssembly 加速 FFT,但普通频谱没必要
最常被忽略的是音频源本身的缓冲策略:audioElement.preload = 'none' 并手动 load() 后再播放,能减少初始解码延迟。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











