CSS 的 counter() 无法响应变量变化做动画,counter-reset: name var(--num) 仅在重排时快照整数值并显示,小数会被截断或忽略,平滑动画需用 requestAnimationFrame、@property 配合 transition 或数字滚动方案。

CSS 本身无法让 counter() 直接响应变量变化做动画,但可以借 counter-reset 中转变量值来“显示”数字——前提是变量是整数,且你接受它只在 JS 触发重排时跳变,而非真正过渡。
为什么 counter-reset: name var(--num) 看起来能用,但不是动画
这个写法确实合法,浏览器会把 --num 的当前值(比如 42)作为计数器初始值传给 counter-reset,再通过 counter(name) 显示出来。但它本质是静态快照:
- 每次修改
--num,CSS 不会自动重算counter(),必须触发重排(例如改 class、改伪元素内容、强制getComputedStyle) -
counter()只读取当前计数器“最终值”,不感知中间过程,所以没有过渡能力 - 若
--num是小数(如42.7),Chrome 会向下取整为42,Firefox/IE 直接当非法值忽略,回退到0
如何用 counter-reset 显示 CSS 变量值(整数限定)
核心是把变量“注入”到 counter-reset 声明中,再用伪元素读取:
.counter {
--num: 123;
counter-reset: num var(--num);
}
.counter::before {
content: counter(num);
}
注意三点:
立即学习“前端免费学习笔记(深入)”;
-
counter-reset必须写在与伪元素同级或父级元素上,不能只写在::before里(否则计数器作用域失效) -
var(--num)必须是整数;若来源是 JS 计算的小数,得先Math.round()或Math.floor()处理 - 要更新数字,JS 需执行:
el.style.setProperty('--num', newNum)+ 强制重排(如el.offsetHeight)才能让counter()刷新
想实现平滑滚动增长?别依赖 counter-reset,换方案
真正带缓动的数字增长,counter-reset + counter() 架构撑不住。现实项目中更可靠的做法:
- 用
requestAnimationFrame控制 DOM 文本更新(轻量、兼容性好、可控制 easing) - 用 CSS
@property注册--count变量 +transition+content: attr(data-count)配合 JS 更新data-count属性(需现代浏览器支持) - 用
clip-path或transform: translateY()滚动一列预设数字(适合固定位数、强调视觉感的场景)
硬要用 CSS 变量驱动动画,@property 是目前唯一能让 --count 被 transition 捕获的机制;counter-reset 只是个“快照式显示层”,不是动画引擎。


















