Welcome to my public account: front-end detective
I have to say, CSS counters are a good thing.
CSS counters have been used in several articles recently. CSS variables can be dynamically displayed through pseudo-elements content
, and many interesting animations can be made. If you are interested, you can review these previous articles:
- Are you still using a timer? CSS can also implement electronic clocks
- Animation synthesis tips! CSS to achieve dynamic countdown effect
- Custom Counter Tips! CSS implements long-press like cumulative animation
The principle is actually very simple, content
Although it does not support direct rendering of CSS variables, it can support counter-reset
count::before {
--percent: 50;
counter-reset: progress var(--percent);
content: counter(progress);
}
Through a transfer, you can make content
also support CSS variables as characters to display
This technique is learned from Zhang Xinxu's article, which is very practical: Tips: How to display CSS var variable values with the help of the content attribute
However, this method has a pity that the CSS counter does not support decimals in the true sense, that is, if the CSS variable is a decimal, it is directly displayed as 0
count::before {
--percent: 50.15;
counter-reset: progress var(--percent);
content: counter(progress);
}
So, how to make content
also support the decimal display of CSS variables, after all, decimals are still required in many cases? For example, if you support decimals, you can easily realize the scrolling animation of numbers
Let's talk about it today
1. Dismantling the principles of CSS
Due to the particularity of CSS counters, only integers are currently supported. After all, natural numbers have no decimals (it does not rule out that custom counters can be implemented in the future). In this case, you can change the way of thinking and split it from the digital form. For example, a decimal, 48.69
can be decomposed into integer part 48
and fractional part 69
, and then linked by decimal point. In this way, they are all integers after splitting, and CSS counters are also supported.
It is implemented by code (for easy understanding, some of the following variables are named in Chinese, which is not recommended for actual production)
count::before {
--整数: 48;
--小数: 69;
counter-reset: 整数计数器 var(--整数) 小数计数器 var(--小数);
content: counter(整数计数器) "." counter(小数计数器);
}
So the question becomes, how to split a decimal?
2. Split CSS variables into integers and decimals
Following the above question, suppose the variable is --percent
, the problem is the following two variables --整数
and --小数
how to calculate from --percent
?
count::before {
--percent: 48.69;
--整数: 48;
--小数: 69;
counter-reset: 整数计数器 var(--整数) 小数计数器 var(--小数);
content: counter(整数计数器) "." counter(小数计数器);
}
It seems easy, but it doesn't seem to be very easy to implement in CSS.
To solve this, you need to understand the types of CSS custom variables . There are many types, listed below
-
<length>
-
<number>
-
<percentage>
-
<length-percentage>
-
<color>
-
<image>
-
<url>
-
<integer>
-
<angle>
-
<time>
-
<resolution>
-
<transform-function>
-
<custom-ident>
-
<transform-list>
Most of the specific types can be seen. We need to use two types here, <number>
and <integer>
, both of which represent numbers, the specific difference is that
-
<number>
represents any number, both integers and decimals -
<integer>
represents an integer number, which can only be an integer, and decimals will be considered illegal
Back here, by default, CSS variables can have any value, but with custom variables @property
you can specify the type of the variable, which can convert invalid variables.
@property - CSS (Cascading Style Sheets) | MDN (mozilla.org)
For example, we need an integer, which can be defined like this, set the syntax
attribute to <integer>
@property --整数 {
syntax: "<integer>"; /*整型*/
initial-value: 0;
inherits: false;
}
This way, the variable will be coerced to an integer. For example, the following --整数
is also set to a decimal
count::before {
--percent: 48.69;
--整数: 48.69;
--小数: 69;
counter-reset: 整数 var(--整数) 小数 var(--小数);
content: counter(整数) "." counter(小数);
}
result...
It turned into 0
?
But it doesn't matter, you need to cooperate with some CSS calculation functions to achieve automatic conversion, such as calc
count::before {
--percent: 48.69;
--整数: calc(48.69);/*使用 CSS 计算后可以转换成整数*/
--小数: 69;
counter-reset: 整数 var(--整数) 小数 var(--小数);
content: counter(整数) "." counter(小数);
}
However, here it becomes 49
, the reason is actually due to rounding, not rounding down . To eliminate this error, we can subtract 0.5
, so the final implementation of the integer part is
@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(小数);
}
The future CSS math functions should also have floor, ceil, etc., you can look forward to it~
Then there is the fractional part. With the integer part, the fractional part is easy. You can subtract the integer part from the whole value and multiply by 100, as shown below
Implementing it in code is
@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(小数);
}
The effect is as follows
The last decimal place is slightly off due to rounding. It doesn't matter, you can correct it and add 0.01
. Secondly, there is a problem, when the decimal place is less than 10, the calculated result may be like this
Then, in this case, dynamic zero padding is required.
The technique of "zero-padding" has been described in detail in this article before: Can CSS also auto-complete strings?
Therefore, you only need to define the counter style after the counter decimal-leading-zero
, which means the decimal leading zero, and the final implementation is as follows
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);
}
In this way, both integers and decimals can be represented by the same variable --percent
, perfect~
3. CSS variable animation
Some people may think, why waste so much effort to realize such a function? Can't you set it directly with js? If it's just a change in numbers, of course, but here, in addition to the better maintainability of CSS single variables , you can also do things that even JS can't do (or cost more), such as transition animation
First of all, to improve it, many decimals are in the form of percentages, that is, within the range of 0~1
, so the previous --percent
may be such a value 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) "%";
}
The effect is as follows
Then, we let this number change randomly through JS
count.addEventListener('click', ev => {
ev.target.style.setProperty("--percent", Math.random());
})
The effect is as follows
However, this is too rigid. We need an animation when the number changes, which can be implemented directly through CSS custom variables
@property --percent {
syntax: "<number>";
initial-value: 0;
inherits: false;
}
count{
/**/
transition: --percent 1s
}
Now look at the effect, it is very easy to realize the scrolling animation of the number
Since the fractional part follows the integer part, for example, the integer changes from 1
to 3
, then the fractional part follows the change for two cycles. Originally this is also very common sense, just like the second of the clock will always be faster than the time, but some people may think that the change is too fast, is there a way to make the fractional part and the integer part independent? Of course, it is also possible, and it is very easy, just set transitions for the integer part and the decimal part respectively.
count{
/**/
transition: --整数 1s, --小数 1s;
}
Now look at the effect and compare it with the above
These two effects can be selected by yourself, only the transition is different
Just imagine, if this effect is implemented with JS, is it still a little troublesome?
Below is the complete code (not much, just a few lines)
@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) "%";
}
You can also visit the online demo: CSS double num(runjs.work)
RunJS , front-end code creation and sharing online.
4. Summary and Explanation
The above is the whole content, a good little skill, have you learned it?
- CSS variables do not support rendering directly in
content
, but can be achieved with the help of counter initialization - CSS counters do not support decimal initialization
- The implementation principle of CSS counter supporting decimals is to split the decimal into three parts: integer, decimal point and decimal
- CSS custom variables can specify the type of variable, so that a decimal can be converted to an integer through CSS math functions
- The fractional part can be obtained by subtracting the integer part
- The decimal part also needs to pass
decimal-leading-zero
to complete the number of digits - CSS single variables can bring better maintainability on the one hand, and transition animations can be implemented more easily on the other hand
- With the help of
@property
you can easily control the transition and animation of CSS variables
Digital change animation is quite practical in some large-screen data display scenarios. With CSS variables, there is no need to calculate in real time through JS. However, the compatibility is not very good at present, and it is suitable for small-scale use in internal projects (of course, it doesn't matter if you use it directly, it just doesn't support animation). Finally, if you think it's good and helpful to you, please like, bookmark, and forward ❤❤❤
Welcome to my public account: front-end detective
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。