持续进步的同学都关注了 “1024译站 ”
CSS 计数器是由 CSS 维护的变量,这些变量可根据 CSS 规则增加从而跟踪使用次数。我们可以利用这个特性,根据文档位置来调整内容表现,比如显示列表编号。
最近在公司官网就用到了这个特性:
image.png
因为这里的序号只是个装饰,并不强调先后顺序。比起使用真实 DOM 元素显示序号,CSS 计数器更加简洁灵活,万一内容顺序需要调整,序号也不受影响。
有时候我们会看到某些 Dashboard 界面有数字快速滚动的效果,比如招行 App 的账户余额。这种效果怎么实现呢?本文会介绍几种方法。
JavaScript 方案
最简单的莫过于用 setInterval定时器了,定期修改 DOM 内容就行。不过为了实现更平顺的动画效果,更推荐使用 requestAnimationFrame:
function animateValue (obj, start, end, duration ) { let startTimestamp = null ; const step = (timestamp ) => { if (!startTimestamp) startTimestamp = timestamp; const progress = Math .min((timestamp - startTimestamp) / duration, 1 ); 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 );
js.gif
CSS @keyframes 结合 margin
这个思路比较有意思,原理是把数字排成一行,通过动画移动元素位置来显示不同位置的数字:
<div class ="counter" > <div class ="numbers" > <div > 0</div > <div > 1</div > <div > 2</div > <div > 3</div > <div > 4</div > <div > 5</div > <div > 6</div > <div > 7</div > <div > 8</div > <div > 9</div > <div > 10</div > </div > </div >
.counter { width : 100px ; overflow : hidden; }.numbers { width : auto; display : flex; animation : countNumber 4s infinite alternate; animation-timing-function : steps (10); }.numbers div { text-align : center; flex : 0 0 100px ; } @keyframes countNumber { 0% { margin-left : 0px ; } 100% { margin-left : -1000px ; } }
keyframe.gif
CSS 计数器入门版
CSS 计数器使用到以下几个属性:
要使用 CSS 计数器,得先用 counter-reset 创建。结合 CSS 动画 @keyframes,在动画的不同阶段设置不同的递增值,就能实现这个效果:
<div> </div>
div ::after { content : counter (count); animation : counter 3s linear infinite alternate; counter-reset : count 0 ; } @keyframes counter { 0% { counter-increment : count 0 ; } 10% { counter-increment : count 1 ; } 20% { counter-increment : count 2 ; } 30% { counter-increment : count 3 ; } 40% { counter-increment : count 4 ; } 50% { counter-increment : count 5 ; } 60% { counter-increment : count 6 ; } 70% { counter-increment : count 7 ; } 80% { counter-increment : count 8 ; } 90% { counter-increment : count 9 ; } 100% { counter-increment : count 10 ; } }
CSS 计数器高配版
更进一步,如果敢用最新特性,其实有更秀的操作,那就是给 CSS 变量设置动画。这个技巧的核心就是设置 CSS 自定义属性为整数类型,这样就能像其他拥有整数类型值的 CSS 属性一样,可用于 transition中了。
@property --num { syntax: '<integer>' ; initial-value: 0 ; inherits: false ; } div { transition: --num 1 s; counter-reset: num var (--num ); } div:hover { --num : 10000 ; } div::after { content: counter(num ); }
不过需要注意的是,目前只有 Chrome (或者 Chromium 内核的浏览器比如 Edge 和 Opera)支持 @property语法,因此兼容性是个问题。如果你的页面只针对 Chrome(比如 Electron 应用),那就可以放心使用。否则还是用前面的保守方案吧。
小数也能玩动画
前面说的变量都要求是整数,那能不能让小数也支持这种动画呢?答案是可以的。
可以把小数转成整数。步骤原理是:
注册一个整型的 CSS 变量(即--number),指定初始值initial-value。
用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 */
完整代码:
<div> </div>
@property --percent { syntax: "<number>" ; initial-value: 0 ; inherits: false ; }@property --temp { syntax: "<number>" ; initial-value: 0 ; inherits: false ; }@property --v1 { syntax: "<integer>" ; initial-value: 0 ; inherits: false ; }@property --v2 { syntax: "<integer>" ; initial-value: 0 ; inherits: false ; } div { font: 800 40 px monospace; padding: 2 rem; transition: --percent 1 s; --temp: calc(var (--percent) * 100 ); --v1: max(var (--temp) - 0.5 , 0 ); --v2: max((var (--temp) - var (--v1)) * 100 - 0.5 , 0 ); counter-reset: v1 var (--v1) v2 var (--v2); } div::before { content: counter(v1) "." counter(v2, decimal-leading-zero) "%" ; }
const genNumber = () => { document .querySelector("div" ).style.setProperty("--percent" , Math .random()); }; setInterval(genNumber, 2000 ); setTimeout(genNumber);
decimal.gif
顺手点“在看”,每天早下班;转发加关注,共奔小康路~