【译】CSS动画-数字跳动

原文链接:Animating Number Counters | CSS-Tricks (挑有用的部分翻译)

作者 Carter Li 翻译 Sirice

注:本文中使用的 code-pen jsrun 等嵌入式代码运行组件受浏览器版本的直接限制,Chrome 78 及以下版本无法正确运行,请更新您的浏览器版本。

数字跳动动画,指的是从 1 跳到 2,2 跳到 3,3 跳到 4……的页面效果,广泛用于 dashboard,可以对数字增加观感上的活力。以前的方法普遍是用 JS 更改 DOM 数字,现在提出一种新方法去用纯 CSS实现。

pic

JavaScript 实现方案

我们可以用纯逻辑的思路,用 JS 的setInterval()方法改变数字。但还有一个更奇特 (fancier) 的方法来实现:

<div id="value">100</div>
/**
 * timeStamp 事件属性可返回一个时间戳。指示发生事件的日期和时间
 * (timestamp - startTimestamp) / duration
 * 这句 timestamp 会持续变,减去初始时间戳除以持续时间即可代替setInterval()
*/

function animateValue(obj, start, end, duration) {
    let startTimestamp = null;

    const step = (timestamp) => {
        //  console.log("timestamp",timestamp)
        if (!startTimestamp) startTimestamp = timestamp;
        const progress = Math.min((timestamp - startTimestamp) / duration, 1);
        //  console.log("progress",progress)
        obj.innerHTML = Math.floor(progress * (end - start) + start);
        if (progress < 1) {
            window.requestAnimationFrame(step);
        }
    };
    window.requestAnimationFrame(step);
}

const obj = document.getElementById("value");
animateValue(obj, 100, 0, 5000);

注:这里有 2 个知识点:

  • window.requestAnimationFrame(callback)
  • timeStamp 对象

Pure CSS 实现

跟进最新的浏览器对 CSS 的特性支持:CSS.registerProperty@property,我们可以使用 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);
}

注:这个特性是 Chrome >78 以上新支持的,因此这个方法对于旧版本浏览器并不友好。

CSS content 属性能用于显示中心的数字,但还需要 counter 将数字转换成字符因为 content 只接受输出为 <string> 的值。


类型化的 CSS 变量也可以用在 @keyframes 中。

这个方法的缺点是,counters 只支持整数,意味着小数是不行的,所以我们要想办法把整数和小数部分分开显示。

怎么对小数做这个效果?

我们可以将小数转换为整数,只要按以下步骤进行:

  1. 声明一个整数类型的 CSS 变量 (<integer> CSS variable),用 initial-value 赋值。
  2. 然后用 calc() 对这个值取整:--integer: calc(var(--number))
@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 */

同理,我们可以抽出小数部分。然后将其用 counter 转换为字符串。

content: "string1" var(--string2) counter(--integer)...;

以下为一个完整示例

其他示例

这是一个将字符应用同样效果的示例,将“CSS”变为“YES”

另一个 tip:

我们可以使用 JavaScript 调试捕获自定义属性的计算值的值

getComputedStyle(element).getPropertyValue('--variable')

其他实现方式参考