真翻滚无法用@keyframes+counter-increment实现,因counter无中间态、@keyframes不支持位级动画;须用10行等宽数字纵向堆叠+translateY位移裁剪模拟,JS控制class切换更务实。

用 @keyframes + counter-increment 做不了真翻滚
纯 CSS 无法让数字“逐位翻滚”(比如 19 → 20 时个位从 9 翻到 0、十位从 1 滚到 2),因为 counter-increment 只触发整数变更,没有中间态;@keyframes 也无法对数字字符做位级动画。所谓“CSS 翻滚计数”,本质是视觉模拟——靠多层数字堆叠 + 位移裁剪实现。
核心思路:用 10 行数字字体 + transform: translateY() 滚动
把 0–9 十个数字纵向排成一列(类似老式机械计数器的数字带),再用容器设 overflow: hidden 裁剪,通过 transform: translateY() 控制哪一行露出来。每个数位独立控制,才能实现错峰翻滚效果。
- 必须用等宽字体(如
'Courier New', monospace),否则数字错位 - 每行高度 = 字体大小(
font-size),且需精确设置line-height: 1 - 容器高度必须严格等于单行高度,不能依赖 padding/margin 计算
- 动画时长建议 ≥ 0.3s,太短人眼跟不上翻滚过程
.digit-roll {
font-family: 'Courier New', monospace;
font-size: 48px;
line-height: 1;
height: 48px;
overflow: hidden;
display: inline-block;
}
.digit-roll span {
display: block;
transform: translateY(-288px); /* -6 * 48px,显示数字 6 */
}用 CSS 变量驱动翻滚:避开 calc() 在 transform 中的限制
CSS 变量不能直接参与 transform: translateY(calc(var(--n) * -48px)) 运算(多数浏览器不支持 calc 在 transform 里嵌套变量),得换方式:
- 预定义 10 个
transform类,如.n-0到.n-9,各自写死translateY(0)~translateY(-432px) - 用 JS 根据目标数字动态切换 class,避免 runtime 计算
- 若坚持纯 CSS,可用
@property(Chrome 108+)声明受控变量,再配合transition,但兼容性差
更务实的做法:JS 控制 class,CSS 只管动画曲线和位移,分工清晰。
立即学习“前端免费学习笔记(深入)”;
多位数字同步翻滚时的常见错位问题
多个 .digit-roll 元素如果共用同一段动画,会因 DOM 渲染时机或 JS 执行顺序导致翻滚不同步,看起来像“卡顿”或“跳变”。
- 每个数位的
animation-delay需按位错开,例如百位延时 0.05s、十位 0.1s、个位 0.15s - 避免用
animation: roll 0.4s ease-out直接触发,改用animation: roll 0.4s ease-out forwards并确保forwards生效 - 初始状态要设为
transform: translateY(0),否则首帧可能闪现错误数字 - 数字变化频繁时(如每秒更新多次),需用
requestAnimationFrame节流,否则 CSS 动画队列堆积
翻滚效果的“真实感”不在速度,而在位与位之间的微小时间差和 easing 曲线——这点 JS 控制比纯 CSS 更稳。


















