纯CSS数字逐位跳动动画需用counter-increment配合steps(10,end)实现,每位数字独立span包裹,移动端需translateZ(0)硬件加速;transform滚动方案存在兼容与对齐问题,推荐CSS+极简JS混合方案控制自定义属性。

用 counter-increment + @keyframes 实现数字逐位跳动
纯 CSS 实现数字滚动动画,核心是利用 CSS 计数器动态更新内容,再配合 animation 触发重排。它不依赖 JS,适合轻量、静态数字(比如「12345」一次性展示),但无法实时响应 JS 变量变化。
关键点在于:每个数字位需独立包裹,用 counter-reset 和 counter-increment 控制值,再通过 ::before 的 content 输出;跳动感靠 steps(10, end) 实现逐帧切换,避免平滑过渡。
- 必须为每位数字写一个
<span>,不能只给整个数字容器设动画 -
steps(10, end)中的10对应 0–9 十个状态,end确保在每步结束时才切换,否则会看到模糊中间帧 - 移动端需加
-webkit-transform: translateZ(0)强制硬件加速,否则 iOS Safari 动画卡顿明显
为什么不用 transform: translateY() 滚动数字条
常见方案是把「0123456789」拼成一列,用 transform: translateY() 上下移动——这看似直观,但实际在移动端极易出问题:
- iOS Safari 对
transform+will-change组合的渲染优化不稳定,快速动画时出现闪烁或白屏 - 数字高度稍有差异(如字体中「1」和「0」基线不同)会导致跳动错位,需手动微调
line-height和vertical-align - 若数字含小数点或负号,整条数字图谱需重新对齐,维护成本陡增
- 无法单独控制某一位的动画延迟(比如实现“从左到右逐位跳动”),得靠 JS 驱动,失去纯 CSS 优势
兼容性与性能取舍:iOS 15+ 可用 animate() API,但别默认启用
CSS animate() 方法(即 JS 调用 element.animate() 配合 keyframes)在 iOS 15.4+ 支持数字属性动画,例如直接动画 counter-set。但它不是稳定选项:
立即学习“前端免费学习笔记(深入)”;
-
counter-set不是可动画属性,实际要靠custom属性 +@property声明,而@property在 iOS 16.4 之前不支持inherits: false,导致继承污染 - 安卓 Chrome 对
@property的初始值解析有 bug,可能首次动画跳变异常 - 真机测试发现:开启
prefers-reduced-motion时,animate()不自动降级,需额外监听并 fallback 到静态显示
真实项目里更推荐「CSS + 极简 JS」混合方案
完全纯 CSS 适合固定数字,但业务中数字常来自接口或用户交互。这时用 10 行内联 JS 控制 CSS 自定义属性最稳:
const numEl = document.querySelector('.digit-anim');
numEl.style.setProperty('--target', '789');
// 对应 CSS:content: counter(digit) ""; counter-set: digit var(--target);
这样做既保留 CSS 动画的流畅性,又规避了 JS 直接操作 DOM 文本引发的重排。注意两个细节:
- JS 设置
--target后,需确保 CSS 中该变量已声明为@property(带syntax: "<integer>"),否则动画无效 - 多位数字要分别绑定变量(如
--target-digit1,--target-digit2),避免单变量触发全部重绘 - 若数字变化频繁(如每秒多次),建议加节流,否则 iOS WebKit 可能丢帧
真正难的不是让数字动起来,而是让每一位在各种屏幕缩放、字体加载、暗色模式切换下都保持对齐和节奏一致——这些细节往往要靠真机反复调试,而不是照搬代码片段。


















