欢送关注我的公众号:前端侦探
不得不说,CSS 计数器是个好货色。
最近在几篇文章中都用到了 CSS 计数器,能够将 CSS 变量通过伪元素 content
动静展现进去,还能够做出很多乏味的动画。有趣味的能够先回顾一下之前的这几篇文章:
- 还在应用定时器吗?CSS 也能实现电子时钟
- 动画合成小技巧!CSS 实现动感的倒计时成果
- 自定义计数器小技巧!CSS 实现长按点赞累积动画
原理其实很简略,content
尽管自身不反对 CSS 变量间接渲染,然而能够反对counter-reset
count::before {
--percent: 50;
counter-reset: progress var(--percent);
content: counter(progress);
}
通过一次直达,就能够让 content
也能反对 CSS 变量作为字符展现了
这个技巧是通过张鑫旭的这篇文章理解的,十分实用:小 tips: 如何借助 content 属性显示 CSS var 变量值
然而,这个办法有个比拟遗憾的中央就是,CSS 计数器不反对真正意义上的小数,也就是如果 CSS 变量为小数的话,间接展现为 0
count::before {
--percent: 50.15;
counter-reset: progress var(--percent);
content: counter(progress);
}
那么,如何让 content
也反对 CSS 变量的小数展现呢,毕竟很多状况下还是须要小数的?比方上面这个,如果反对了小数,就能够轻易的实现数字的滚动动画
明天一起来探讨一下
一、CSS 原理拆解
CSS 计数器因为特殊性,目前都是仅反对整数的,毕竟天然个数是没有小数的(不排除当前自定义计数器能够实现)。既然这样,能够换一种思路,从数字状态上进行拆分。比方一个小数,48.69
能够分解成整数局部 48
和小数局部69
,而后再通过小数点链接起来。这样拆分后就都是整数了,CSS 计数器也是反对的
用代码实现就是(便于了解,以下的一些变量都是中文命名的,理论生产不举荐)
count::before {
-- 整数: 48;
-- 小数: 69;
counter-reset: 整数计数器 var(-- 整数) 小数计数器 var(-- 小数);
content: counter(整数计数器) "." counter(小数计数器);
}
所以问题就变成了,如何将一个小数进行拆分呢?
二、CSS 变量拆分成整数和小数
接着下面的问题,假如变量是 --percent
,问题就是上面两个变量-- 整数
和-- 小数
如何通过 --percent
计算而来呢?
count::before {
--percent: 48.69;
-- 整数: 48;
-- 小数: 69;
counter-reset: 整数计数器 var(-- 整数) 小数计数器 var(-- 小数);
content: counter(整数计数器) "." counter(小数计数器);
}
看似很容易,但在 CSS 中如同并不怎么好实现。
为了解决这个,须要理解一下 CSS 自定义变量的类型。类型有很多,上面列举一下
<length>
<number>
<percentage>
<length-percentage>
<color>
<image>
<url>
<integer>
<angle>
<time>
<resolution>
<transform-function>
<custom-ident>
<transform-list>
大部分能能够看出具体的类型,咱们这里须要用到的就两种,<number>
和<integer>
,两者都示意数字,具体的区别在于
<number>
示意任意的数字,整数和小数都能够<integer>
示意整型数字,只能是整数,小数会认为不非法
回到这里,默认状况下,CSS 变量能够是任意值,然而通过自定义变量 @property
能够指定变量的类型,它能够对不非法的变量进行转换。
@property – CSS(层叠样式表)| MDN (mozilla.org)
比方,咱们须要一个整数,能够这样来定义,将 syntax
属性设置为 <integer>
就能够了
@property -- 整数 {
syntax: "<integer>"; /* 整型 */
initial-value: 0;
inherits: false;
}
这样,这个变量会被强制转换成整数。比方,上面给 -- 整数
也设置成一个小数
count::before {
--percent: 48.69;
-- 整数: 48.69;
-- 小数: 69;
counter-reset: 整数 var(-- 整数) 小数 var(-- 小数);
content: counter(整数) "." counter(小数);
}
后果 …
竟然间接变成了 0
?
不过没关系,须要能够配合一些 CSS 计算函数实现主动转换,比方calc
count::before {
--percent: 48.69;
-- 整数: calc(48.69);/* 应用 CSS 计算后能够转换成整数 */
-- 小数: 69;
counter-reset: 整数 var(-- 整数) 小数 var(-- 小数);
content: counter(整数) "." counter(小数);
}
然而,这里变成了 49
,起因 其实是四舍五入造成的,并不是向下取整。为了打消这种误差,能够再减去0.5
,所以整数局部的最终实现就是
@property -- 整数 {
syntax: "<integer>";
initial-value: 0;
inherits: false;
}
count::before {
--percent: 48.69;
-- 整数: calc(var(--percent) - 0.5);
-- 小数: 69;
counter-reset: 整数 var(-- 整数) 小数 var(-- 小数);
content: counter(整数) "." counter(小数);
}
将来的 CSS 数学函数应该也会有 floor、ceil 这样的,能够期待一下~
而后是小数局部,有了整数局部,小数局部就容易了,能够用整个值减去整数局部,而后乘以 100,示意如下
用代码实现就是
@property -- 小数 {
syntax: "<integer>";
initial-value: 0;
inherits: false;
}
count::before {
--percent: 48.69;
-- 整数: calc(var(--percent) - 0.5);
-- 小数: calc((var(--percent) - var(-- 整数)) * 100 - 0.5);
counter-reset: 整数 var(-- 整数) 小数 var(-- 小数);
content: counter(整数) "." counter(小数);
}
成果如下
前面最末位的小数因为四舍五入的关系略微有些偏差,没关系,能够修改一下,加上 0.01
就行了。其次,还有一个问题,当小数位小于 10 的时候,计算出的后果可能是这样
那么,这种状况就须要动静补零了。
对于“补零”的技巧,之前在这篇文章中有过具体介绍:CSS 也能主动补全字符串?
所以,只须要在计数器前面定义一下计数器款式decimal-leading-zero
,示意十进制前置零,最终实现如下
count::before {
--percent: 48.69;
-- 整数: calc(var(--percent) - 0.5);
-- 小数: calc((var(--percent) - var(-- 整数)) * 100 - 0.5 + 0.01);
counter-reset: 整数 var(-- 整数) 小数 var(-- 小数);
content: counter(整数) "." counter(小数, decimal-leading-zero);
}
这样整数和小数都能够用同一个变量 --percent
示意进去了,完满~
三、CSS 变量动画
有人可能会感觉,为啥要废这么大劲去实现这样一个性能?用 js 间接设置不行吗?如果仅仅是数字的变动,那当然能够,但在这里,除了 CSS 繁多变量带来更好的可维护性外,还能够做到连 JS 也难以做到(或者说老本更高)的事件,比方 过渡动画
首先,再改良一下,很多小数都是百分比模式的,也就是 0~1
范畴内,所以后面 --percent
可能是这样的值0.4869
count::before {
--percent: 0.4869;
-- 百分比: calc(var(--percent) * 100);
-- 整数: calc(var(-- 百分比) - 0.5);
-- 小数: calc((var(-- 百分比) - var(-- 整数)) * 100 - 0.5 + 0.01);
counter-reset: 整数 var(-- 整数) 小数 var(-- 小数);
content: counter(整数) "." counter(小数, decimal-leading-zero) "%";
}
成果如下
而后,咱们通过 JS 让这个数字随机变动
count.addEventListener('click', ev => {ev.target.style.setProperty("--percent", Math.random());
})
成果如下
然而,这样太死板了,咱们须要数字变动的时候有个动画,能够间接通过 CSS 自定义变量实现
@property --percent {
syntax: "<number>";
initial-value: 0;
inherits: false;
}
count{
/**/
transition: --percent 1s
}
当初看看成果,十分轻松的就实现了数字的滚动动画
小数局部因为是追随整数局部的,比方整数从 1
变为3
,那么小数局部就追随变动两个循环。原本这个也十分合乎常理,就像时钟的秒永远要比分要转的快一样,然而有人可能感觉变的太快了,有没有方法让小数局部和整数局部独立开来呢?当然也是能够的,而且非常容易,只须要给整数局部和小数局部别离设置过渡就行了
count{
/**/
transition: -- 整数 1s, -- 小数 1s;
}
当初再看看成果,和下面比照一下
这两种成果能够自行抉择,仅仅只是过渡的不同
试想一下,如果这个成果用 JS 来实现,是不是还有点点麻烦呢?
上面是残缺代码(不多,就这么几行)
@property --percent {
syntax: "<number>";
initial-value: 0;
inherits: false;
}
@property -- 整数 {
syntax: "<integer>";
initial-value: 0;
inherits: false;
}
@property -- 小数 {
syntax: "<integer>";
initial-value: 0;
inherits: false;
}
count {
--percent: 0.4512;
font-size: 60px;
font-weight: bolder;
cursor: pointer;
font-family: 'Courier New', Courier, monospace;
-- 百分比: calc(var(--percent) * 100);
-- 整数: calc(var(-- 百分比) - 0.5);
-- 小数: calc((var(-- 百分比) - var(-- 整数)) * 100 - 0.5 + 0.01);
counter-reset: 整数 var(-- 整数) 小数 var(-- 小数);
transition: -- 整数 1s, -- 小数 1s;
}
count::before {content: counter(整数) "." counter(小数, decimal-leading-zero) "%";
}
你也能够拜访线上 demo:CSS double num(runjs.work)
RunJS,前端代码在线创作与分享。
四、总结和阐明
以上就是全部内容了,一个还不错的小技巧,你学会了吗?
- CSS 变量不反对间接在
content
中渲染,然而能够借助计数器初始化来实现 - CSS 计数器不反对小数初始化
- CSS 计数器反对小数的实现原理在于将小数拆分为整数、小数点、小数三个局部
- CSS 自定义变量能够指定变量的类型,这样通过 CSS 数学函数能够将一个小数转换成整数
- 小数局部能够通过减去整数局部失去
- 小数局部还须要通过
decimal-leading-zero
补全位数 - CSS 繁多变量一方面能够带来更好的可维护性,另一方面还能够更轻易地实现过渡动画
- 借助
@property
能够很不便的管制 CSS 变量的过渡和动画
数字变动动画在一些数据大屏展现的场景下还是挺实用的,有了 CSS 变量,再也不须要通过 JS 去实时计算了。不过目前兼容性还不是太好,适宜外部我的项目小范畴应用(当然间接用了不要紧,不反对的只是没有动画而已)。最初,如果感觉还不错,对你有帮忙的话,欢送点赞、珍藏、转发❤❤❤
欢送关注我的公众号:前端侦探