35
头图
Welcome to my public account: Front-end detective

Many times, you will encounter the need for string completion. A typical example is the zero-fill operation in time or date, such as

2021-12-31
2022-03-03

The usual practice is

if (num < 10) {
  num = '0' + num
}

Later, native completion methods padStart() and padEnd() appeared in JS, as follows

'3'.padStart(2, '0')
// 结果是 ’03‘
'12'.padStart(2, '0')
// 结果是 ’12‘

In fact, this effect can also be achieved in CSS, and there are a variety of solutions, let's take a look, I believe you can have a different experience

1. flex-end alignment

Let's first introduce a relatively easy-to-understand solution, which is also very simple, assuming that the HTML is like this

<span>2</span>
-
<span>28</span>

Under normal circumstances, a monospaced font will also be set, which looks more harmonious and beautiful.

span{
  font-family: Consolas, Monaco, monospace;
}

image.png

We need to generate a "0" with a pseudo-element before the number

span::before{
  content: '0'
}

image.png

Next, set a fixed width for the element. Since it is a monospaced font, it can be directly set to 2ch . Pay attention to this ch unit, which represents the width of the character 0 (for those interested, you can refer to this article: monospaced font is in Application in web layout and CSS3 ch unit hehe ), and then set right alignment on the line

span{
  /**/
  display: inline-flex;
  width: 2ch;
  justify-content: flex-end;
}

image.png

The principle is very simple, put 3 characters in a space of 2 characters width, and right-align, will it automatically squeeze out the leftmost 0 ? Then go beyond hiding

image.png

The complete code is as follows

span::before{
  content: '0'
}
span{
  display: inline-flex;
  width: 2ch;
  justify-content: flex-end;
  overflow: hidden;
}

2. Dynamic calculation of CSS variables

Since CSS cannot get the text content of the label, it is necessary to build a CSS variable to pass it on, as follows

<span style="--num:2">2</span>
-
<span style="--num:12">28</span>

After getting the variable through var(--num) , a series of logical judgments can be made. Then, how to automatically fill in zeros when it is less than 10?

Also we need to generate a "0" with a pseudo-element before the number

span::before{
  content: '0'
}

Then, you only need to dynamically hide this pseudo-element according to CSS variables, first set the transparency, as follows

span::before{
  /**/
  opacity: calc(10 - var(--num));
}

The effect is as follows

image.png

The specific logic is

  • When --num is equal to 10, the calculated value of transparency is 0 , rendering directly according to 0
  • When --num is greater than 10, the calculated value of transparency is , the negative value of , which will be rendered as 0
  • When --num is less than 10, the calculated value of transparency is , the value of greater than or equal to 1, which will be rendered according to 1

Therefore, the final performance is that is invisible when it is greater than or equal to 10, and is visible when it is less than 10.

However, this is still a bit problematic, the transparency will not affect the position of the element, as follows

image.png

How to eliminate this position? There are many methods, the method of margin-left is adopted here, as follows

span::before{
  /**/
  margin-left: clamp(-1ch, calc((9 - var(--num)) * 1ch),0ch);
}

clamp is used here, you can understand it as an interval, there are 3 values [Min, Val, Max] , the front and back are the minimum and maximum values, and the middle is a variable value (note that this is compared with 9), so the logic here is

  • When --num is greater than or equal to 10, it is assumed to be 15, the intermediate calc value is calculated as -5ch , and the clamp value is the minimum value -1ch
  • When --num is less than 10, it is assumed to be 5, the intermediate calc value is calculated as 5ch , the clamp value is the maximum value 0ch

Therefore, the final performance is when it is greater than or equal to 10, the margin-left is -1ch, and when it is less than 10, the margin-left is 0

That's more perfect

image.png

The complete code is as follows

span::before{
  content: '0';
  opacity: calc(10 - var(--num));
  margin-left: clamp(-1ch, calc((9 - var(--num)) * 1ch),0ch);
}

Third, define the counter style

This effect can also be achieved by using a counter. First, look at the default counter effect. We need to hide the original text and use the counter to display CSS variables through pseudo elements. For this technique, you can refer to this article: Tips: How to Display the CSS var variable value with the help of the content attribute, as follows

span::before{
  counter-reset: num var(--num);
  content: counter(num);
}

image.png

Next, you need to use the second parameter <counter-style> of counter , the counter style. What is this for? I believe that everyone has used an attribute list-style-type , which is similar to this, and can define the style of the sequence, such as the order of lowercase English letters

list-style-type: lower-latin;

image.png

Here we need a counter that automatically fills zeros within 10. There is just one ready-made, called decimal-leading-zero . The translation is, decimal leading zero

list-style-type: decimal-leading-zero;

image.png

Back here, what needs to be done is very simple, just add this parameter, the complete code is as follows

span::before{
  counter-reset: num var(--num);
  content: counter(num, decimal-leading-zero);
}

The effect is as follows

Kapture 2022-03-02 at 20.37.05.gif

Fourth, the expansion of the counter

The above counter only works with 2 digits, what if you need 3 digits? For example

001、002、...、010、012、...、098、099、100

padStart in JS can specify the number of digits after padding

'1'.padStart(3, '0')
// 结果是 ’001‘
'99'.padStart(3, '0')
// 结果是 ’099‘
'101'.padStart(3, '0')
// 结果是 ’101‘

In fact, there is also such a capability in CSS, called @counter-style/pad , strictly speaking, this is the official completion scheme, and the syntax is very similar

pad: 3 "0";

However, this needs to be used on a custom counter, that is, @counter-style , if you are interested, you can refer to this article by Mr. Zhang: CSS @counter-style rules are introduced in detail , here is a brief introduction to the usage, assuming Define a counter called pad-num , implemented as follows

@counter-style pad-num {
    system: extends numeric;
    pad: 3 "0";
}

The syntax is as follows: system here means "system", which is some built-in counters. For example, extends numeric is used here, the latter numeric means the digital technology system, and the former extends means extension, based on this, and then pad: 3 "0" and JS's The meaning is the same, indicating that the place where there are less than 3 digits is filled with "0"

Then apply it to the counter:

span::before{
  counter-reset: num var(--num);
  content: counter(num, pad-num);
}

The effect is as follows:

Kapture 2022-03-03 at 15.57.33

Of course, this compatibility is slightly poor, according to actual needs

The complete code above can be accessed at CSS pad(codepen.io)

image-20220303163644336

Fifth, to summarize

The three CSS string completion methods have been introduced above. Have you learned a few more tricks? Each of these methods has its own advantages and disadvantages, and compare their advantages and disadvantages:

  1. The first solution is very easy to understand and easy to expand. If you need to complete 3 bits, you only need to change the overall width. The disadvantage is that it relies on monospaced fonts.
  2. The second scheme is more in line with JS logic and more flexible, but the disadvantage is that the calculation is more verbose, and the fault tolerance of CSS values must also be considered.
  3. The third solution is recommended by me. It does not require calculation and does not depend on the layout. There may not be many students who know it, and if you want to customize the counter, the compatibility is a bit poor.

Regarding the advantages of CSS implementation, there are many advantages, such as easier maintenance, almost no error reporting, more concise code, etc. If you learn it, use it in your project quickly. Finally, if you think it's good and helpful to you, please like, bookmark, and forward ❤❤❤

Welcome to my public account: Front-end detective

XboxYan
18.1k 声望14.1k 粉丝