欢送关注我的公众号:前端侦探
不得不说,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 去实时计算了。不过目前兼容性还不是太好,适宜外部我的项目小范畴应用(当然间接用了不要紧,不反对的只是没有动画而已)。最初,如果感觉还不错,对你有帮忙的话,欢送点赞、珍藏、转发❤❤❤
欢送关注我的公众号:前端侦探