You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用CSS实现基于BPM与节拍数的节拍器动画?

纯CSS实现节拍器动画方案

需求可行性结论

纯CSS可以实现你的需求,但纯原生CSS无法自动适配任意节拍数(BEATS),需要借助CSS预处理器(如Sass)来动态生成对应数量的关键帧;如果仅针对固定几种节拍数(如4/3/2拍),纯原生CSS完全可以实现。

核心原理

  1. 动画时长计算:每小节总时长 = (60s / BPM) * BEATS,单拍时长 = 60s / BPM
  2. 关键帧拆分:第一拍使用特殊颜色,其余节拍复用统一颜色,通过百分比位置控制每一拍的颜色切换时机
  3. 节拍数字显示:利用CSS计数器(counter-reset/counter-increment)配合伪元素实现,替代无效的content动画写法

方案1:纯原生CSS(支持固定4拍)

修正你代码中的错误,实现可通过变量调整BPM的4拍节拍器:

:root {
  --BPM: 120;          /* 每分钟节拍数,可修改 */
  --BEATS: 4;          /* 固定4拍 */
  --primary-color: #8FF; /* 第一拍颜色 */
  --beat-color: #08F;   /* 普通节拍颜色 */
  --bg-color: #000;     /* 底色 */
  /* 计算每小节总动画时长 */
  --cycle-duration: calc((60 / var(--BPM)) * var(--BEATS) * 1s);
}

.metronome {
  color: white;
  text-align: center;
  font-size: 5rem;
  background-color: var(--bg-color);
  /* 初始化节拍计数器 */
  counter-reset: beat-counter 0;
  /* 同步运行背景色和计数器动画 */
  animation: beat-bg var(--cycle-duration) infinite,
             beat-counter var(--cycle-duration) infinite steps(var(--BEATS));
}

/* 用伪元素显示节拍数字 */
.metronome::before {
  content: counter(beat-counter);
}

/* 背景色切换动画 */
@keyframes beat-bg {
  /* 第一拍 */
  0% { background-color: var(--primary-color); }
  calc((100% / var(--BEATS)) - 0.01%) { background-color: var(--primary-color); }
  calc(100% / var(--BEATS)) { background-color: var(--bg-color); }

  /* 第二拍 */
  calc(100% / var(--BEATS)) { background-color: var(--beat-color); }
  calc((2 * 100% / var(--BEATS)) - 0.01%) { background-color: var(--beat-color); }
  calc(2 * 100% / var(--BEATS)) { background-color: var(--bg-color); }

  /* 第三拍 */
  calc(2 * 100% / var(--BEATS)) { background-color: var(--beat-color); }
  calc((3 * 100% / var(--BEATS)) - 0.01%) { background-color: var(--beat-color); }
  calc(3 * 100% / var(--BEATS)) { background-color: var(--bg-color); }

  /* 第四拍 */
  calc(3 * 100% / var(--BEATS)) { background-color: var(--beat-color); }
  calc(100% - 0.01%) { background-color: var(--beat-color); }
  100% { background-color: var(--bg-color); }
}

/* 计数器递增动画 */
@keyframes beat-counter {
  0% { counter-increment: beat-counter 1; }
  calc(100% / var(--BEATS)) { counter-increment: beat-counter 1; }
  calc(2 * 100% / var(--BEATS)) { counter-increment: beat-counter 1; }
  calc(3 * 100% / var(--BEATS)) { counter-increment: beat-counter 1; }
  100% { counter-reset: beat-counter 0; }
}

方案2:Sass预处理器(支持任意节拍数)

通过Sass的循环语句动态生成对应BEATS数量的关键帧,完全适配任意节拍数:

$BPM: 120;
$BEATS: 4;
$primary-color: #8FF;
$beat-color: #08F;
$bg-color: #000;
$cycle-duration: (60 / $BPM) * $BEATS + s;

.metronome {
  color: white;
  text-align: center;
  font-size: 5rem;
  background-color: $bg-color;
  counter-reset: beat-counter 0;
  animation: beat-bg $cycle-duration infinite,
             beat-counter $cycle-duration infinite steps($BEATS);
}

.metronome::before {
  content: counter(beat-counter);
}

@keyframes beat-bg {
  /* 第一拍 */
  0% { background-color: $primary-color; }
  #{(100% / $BEATS) - 0.01%} { background-color: $primary-color; }
  #{100% / $BEATS} { background-color: $bg-color; }

  /* 循环生成其余节拍的关键帧 */
  @for $i from 2 through $BEATS {
    #{($i - 1) * 100% / $BEATS} { background-color: $beat-color; }
    #{($i * 100% / $BEATS) - 0.01%} { background-color: $beat-color; }
    #{$i * 100% / $BEATS} { background-color: $bg-color; }
  }
}

@keyframes beat-counter {
  0% { counter-increment: beat-counter 1; }
  /* 循环生成计数器递增的关键帧 */
  @for $i from 2 through $BEATS {
    #{($i - 1) * 100% / $BEATS} { counter-increment: beat-counter 1; }
  }
  100% { counter-reset: beat-counter 0; }
}

关键修正说明

  1. 你之前代码中在普通元素的@keyframes里使用content是无效的,content仅支持伪元素(::before/::after),改用CSS计数器实现节拍数字显示更合理。
  2. 动画时长通过CSS变量/Sass变量动态计算,直接修改--BPM或$BPM即可调整速度。
  3. 若要实现平滑闪烁而非跳变,只需去掉steps(var(--BEATS)),让动画自然过渡即可。

内容的提问来源于stack exchange,提问作者Parduz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 02:36:05