数字动画,例如,想象一个数字从 1 变成 2,然后从 2 变成 3,然后从 3 变成 4,依此类推,持续指定时间。就像一个计数器,只不过由我们用于 Web 上其他设计动画的相同类型的动画控制。这在设计仪表盘等内容时可能很有用,可以为数字增添一点活力。令人惊奇的是,现在可以在 CSS 中完成此操作,无需太多技巧。如果您愿意,可以直接跳转到新的解决方案,但首先让我们看看我们过去是如何做到的。

一种相当合乎逻辑的数字动画方法是通过 JavaScript 更改数字。我们可以做一个相当简单的setInterval
,但这里有一个更高级的答案,带有一个接受开始、结束和持续时间的函数,因此您可以将其视为动画
仅使用 CSS,我们可以使用 CSS 计数器通过在不同的关键帧中调整计数来为数字制作动画
另一种方法是将所有数字排成一行,并为它们制作动画,一次只显示一个
这些示例中的一些重复代码可以使用像 Pug 用于 HTML 或 SCSS 用于 CSS 的预处理器,这些预处理器提供循环来使它们可能更容易管理,但出于目的而使用原生代码,以便您可以看到基本思想。
新的 CSS 解决方案
随着最近对CSS.registerProperty
和 @property
的支持,我们可以为 CSS 变量制作动画。诀窍是将 CSS 自定义属性声明为整数;这样就可以像任何其他整数一样对其进行插值(例如在过渡中)。
@property --num {
syntax: '<integer>';
initial-value: 0;
inherits: false;
}
div {
transition: --num 1s;
counter-reset: num var(--num);
}
div:hover {
--num: 10000;
}
div::after {
content: counter(num);
}
重要说明:在撰写本文时,此@property
语法仅在 Chrome(以及其他基于 Chromium 的浏览器,如 Edge 和 Opera)中受支持,因此它不适用于所有浏览器。如果您正在构建仅适用于 Chrome 的内容(例如 Electron 应用程序),那么它立即很有用,否则,请等待。上面演示的示例支持范围更广。
CSS content
属性可用于显示数字,但我们仍然需要使用counter
将数字转换为字符串,因为content
只能输出<string>
值。
看到我们如何像任何其他动画一样缓动动画了吗?超级酷!
类型化的 CSS 变量也可用于@keyframes
:
缺点是什么?计数器仅支持整数。这意味着小数和分数不在考虑范围内。我们将不得不以某种方式分别显示整数部分和小数部分。
我们可以为小数制作动画吗?
可以将小数(例如--number
)转换为整数。以下是其工作原理
- 注册一个
<integer>
CSS 变量(例如--integer
),并指定initial-value
- 然后使用
calc()
对值进行四舍五入:--integer: calc(var(--number))
在这种情况下,--number
将被四舍五入到最接近的整数,并将结果存储到--integer
中。
@property --integer {
syntax: "<integer>";
initial-value: 0;
inherits: false;
}
--number: 1234.5678;
--integer: calc(var(--number)); /* 1235 */
有时我们只需要整数部分。有一种巧妙的方法可以做到这一点:--integer: max(var(--number) - 0.5, 0)
。这适用于正数。这样甚至不需要calc()
。
/* @property --integer */
--number: 1234.5678;
--integer: max(var(--number) - 0.5, 0); /* 1234 */
我们可以以类似的方式提取小数部分,然后使用计数器将其转换为字符串(但请记住,content
值必须是字符串)。要显示连接的字符串,请使用以下语法
content: "string1" var(--string2) counter(--integer) ...
这是一个完整示例,用于为带小数的百分比制作动画
其他提示
因为我们使用的是 CSS 计数器,这些计数器的格式可以采用除数字之外的其他格式。这是一个将字母“CSS”动画化为“YES”的示例!
哦,还有一个提示:我们可以使用 JavaScript 获取自定义属性的计算值来调试值
getComputedStyle(element).getPropertyValue('--variable')
就是这样!CSS 如今的功能真是令人惊叹。
这太聪明了!自定义属性似乎拥有许多社区正在慢慢发现的秘密力量。
谢谢!♥
非常聪明,谢谢。我想为这些示例添加一些可访问性注意事项
这些对键盘用户不起作用,但添加起来很容易(在
<div>
上使用tabindex="0"
使其可聚焦,并在选择器中添加div:hover, div:focus {
以在聚焦时应用动画)。屏幕阅读器在导航时读取初始的、动画前的值 (0)。在聚焦或关键帧示例中,它似乎会在动画过程中获取某个值并将其记住(例如,使用 VoiceOver,它一直告诉我“8”或“61”,即使视觉上它仍然保持在 100)。
我不确定是否有优雅的方法来解决此问题——除了使用两个 div 的笨拙方法。
不过,这种方法的一个优点是:与 JS 版本不同,它可以利用
prefers-reduced-motion
媒体查询,并为患有前庭/运动障碍的人提供最终值,而无需任何动画。感谢您的回复。
这就是过渡的工作方式。我的建议也是
这应该很容易实现
我想一次性为它制作动画,所以我设置了动画迭代次数值为 1,但问题是它会回到零,我怎样才能让它停在最后一个值(即 100%)?
我说的是这个 https://codepen.io/chriscoyier/pen/NWNJpPe。
谢谢。???
animation-fill-mode: forwards;
真的很棒!!但想不止一次地做到这一点。
当我复制 div 4 次并为每个 div 提供 id 来播放动画时
它无法正常播放,只有一个或两个可以工作,或者它们可以工作但具有相同的值,而我有 4 个不同的值,那么如何为 4 个不同的值制作动画呢?
看看我的编辑:https://codepen.io/bgbos/pen/pobZvwJ
我甚至尝试过使用 -num(如您所见)来使其不同。
感谢您的帮助。
您定义了两次
--num
和@keyframes counter
。在解决您的问题之前,您必须修复这些问题和不良的编码风格。好的,所以我们在这里有这段代码:https://codepen.io/bgbos/pen/pobZvwJ
如您所见,它们每个都有一个不同的初始值,必须在该值处停止,但它们都停在一个值上,我不知道为什么,所以请告诉我如何做到这一点?
抱歉代码不好,先生,我完全是新手。
此致。
是否有一种方法可以在页面上使用多个计数器?
可以在 React 中的 styled-components 中使用自定义属性吗?
你好,Carter
谢谢分享。这是一种实现效果的非常棒的方法。
我在我的项目中实践了您的解决方案。
但它似乎在移动设备和 Safari 上不起作用。
是否有解决此棘手问题的办法。
目前只有 Chrome 支持它,并且无法使用 polyfill。
所以不行。
早在 2014 年我就为此编写了一个小程序
https://github.com/yairEO/Do-in
如何阻止计数器下降或重置?我希望计数器停在最终值上。
animation-fill-mode: forwards;
你需要将动画填充模式设置为“forwards”,然后它将停留在最终值上
animation-fill-mode: forwards;
这很棒,但我有一个奇怪的问题。如果我想用它来显示记分牌。我希望数字不要重置为0。有没有办法防止这种情况发生?
数字不是你自己设置的吗?
在使用大数字时注意到一个奇怪的行为 - 计数器始终设置为0,然后在动画结束时跳到最终值。动画的长度没有影响。
div::after {
content: counter(num);
}
div:hover {
–num: 11000000;
}
有没有人有任何想法可能导致这种情况?
这里也有同样的问题,但我的甚至不跳跃,只是停留在0。我绞尽脑汁试图理解为什么我的4个计数器中有2个不工作,尽管代码是相同的,直到我理解这是由于值本身造成的。似乎一旦超过8位数字,这就不起作用了。
有没有人设法弄清楚为什么会发生这种情况,以及是否有可能的解决方案?
在这里提交了一个问题:https://bugs.chromium.org/p/chromium/issues/detail?id=1217506
让我们等待一些回复。
编辑:该问题被分配了优先级2
编辑2:它将在 Chrome 93 中修复
https://bugs.chromium.org/p/chromium/issues/detail?id=1217506#c6
你好!我添加了 animation-fill-mode: forwards;
但我无法让它在最后停止。谁能帮我一下?
我的代码
animation-iteration-count: 1;
这可以绑定到滚动位置吗?例如,我可以让数字计数器随着用户向下滚动而增加,随着用户向上滚动而减少吗?
你需要
IntersectionObserver
我创建了一个使用 IntersectionObserver 的版本,其中包含一些针对旧版浏览器的回退和 prefers-reduced-motion。
进一步解释请访问 https://www.bronco.co.uk/our-ideas/experimenting-with-css-number-counters-with-fallback/