Still using the timer? CSS can also realize electronic clock

Usually we need to make a clock, which must be inseparable from JS timer. Today, let's change our thinking and use CSS to realize a clock, as follows:

You can also access this CSS time (codepen.io) See the actual effect

Of course, I borrowed a little JS for initialization time. The whole clock is run by CSS. There are many tips you may not know. Let's have a look

1, Digital transformation

Let's first look at how numbers change.

In the past, if you want to realize the incremental change of numbers, you may need to prepare these numbers in advance, such as this

<span>
    <i>1</i>
  <i>2</i>
  ...
  <i>59</i>
</span>

Then it is realized by changing the displacement.

However, there is a more concise way to achieve it, that is CSS @property , those who do not understand this can refer to this article: CSS @property, making the impossible possible . What's this for? In short, you can customize the attributes. In this example, you can make the numbers transition and animate like colors. You may not understand it. Just look at the example

Suppose HTML is like this

<span style="--num: 0"></span>

Let's show this user-defined variable in the page. Simple content cannot directly display the user-defined variable. You need to use a timer. If you are interested, please refer to this article: Small tips: how to display the value of CSS var variable with the help of content attribute

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

This number can be changed by: hover

span:hover::after{
  --num: 59
}

Very stiff from 0 to 59, very conventional. If you use CSS property, the situation is different. There are few places that need to be modified. First define -- h, and then give this variable a transition time, as follows

@property --h { 
  syntax: '<integer>';
  inherits: false;
  initial-value: 0;
}
span::after{
  transition: 1s --num;
}

A magical scene happened

Looks incredible? It can be understood that after @ property is defined, the variable itself can set the transition independently, instead of depending on some properties that only support transition (color, width, etc.). You can even add animation. You need to use the steps method to set the animation cycle to infinity, as follows

@keyframes num {
  to {
    --num: 10
  }
}
span{
  animation: num 1s infinite steps(10);
}

The basic operation principle of the clock is like this, an infinite loop CSS animation!

2, Hour, minute and second

Let's look at the specific implementation of hour, minute and second. The HTML is as follows

<div class="time">
  <span class="hour"></span>
  <a class="split">:</a>
  <span class="minitus"></span>
  <a class="split">:</a>
  <span class="seconds"></span>
</div>

Attach initial values to hours, minutes and seconds

@property --h { 
  syntax: '<integer>';
  inherits: false;
  initial-value: 0;
}
@property --m { 
  syntax: '<integer>';
  inherits: false;
  initial-value: 0;
}
@property --s { 
  syntax: '<integer>';
  inherits: false;
  initial-value: 0;
}
.hour::after{
  counter-reset: hour var(--h);
  content: counter(hour);
}
.minitus::after{
  counter-reset: minitus var(--m);
  content: counter(minitus);
}
.seconds::after{
  counter-reset: seconds var(--s);
  content: counter(seconds);
}

The hours, minutes and seconds here have no linkage relationship, so they all need separate animation. Now we need to think about it 🤔, If you use CSS animation to achieve, what is the starting point and duration of each animation?

Yes, that's what you think. The hour hand is 0-23, the duration is 24h, the minute hand is 0-59, the duration is 60min, the second hand is 0-59 and the duration is 60s. However, the time unit in CSS only supports seconds (s) or milliseconds (ms), so it needs to be converted here. The duration is 60s*60*24, 60s*60 and 60s respectively. The specific implementation is as follows:

@keyframes hour {
  to {
    --h: 24
  }
}
@keyframes minitus {
  to {
    --m: 60
  }
}
@keyframes seconds {
  to {
    --s: 60
  }
}
.hour::after{
  counter-reset: hour var(--h);
  content: counter(hour);
  animation: hour calc(60s * 60 * 24) infinite steps(24);
}
.minitus::after{
  counter-reset: minitus var(--m);
  content: counter(minitus);
  animation: minitus calc(60s * 60) infinite steps(60);
}
.seconds::after{
  counter-reset: seconds var(--s);
  content: counter(seconds);
  animation: seconds 60s infinite steps(60);
}

Here, in order to facilitate observation, the time is adjusted 10 times faster (60s = > 6S), as follows:

3, Automatic zeroing of hour, minute and second

There is a problem with the above layout. The change in the width of 1-digit and 2-digit leads to the "shaking" of the clock as a whole, so it is necessary to add a "0" when 1-digit. As for CSS zeroing, three schemes have been mentioned in this article. Since the counter is used here, the method of changing the counter style is directly selected and implemented through decimal leading zero. The specific methods are as follows

.hour::after{
  /**/
  content: counter(hour, decimal-leading-zero);/*Add counter style*/
}

So much more harmonious

4, Time initialization

It started at 00:00:00 just now, so you need to manually specify the initial time. Suppose it is 19:26:30, how to initialize it?

Here, we need to use animation delay to move to the specified position in the future in advance. In order to facilitate control, we use three variables -- dh, -- dm, -- ds to represent the initial time. Note that since animation delay only supports seconds (s) or milliseconds (ms), it also needs to be converted. The implementation is as follows

:root{
  --dh: 19;
  --dm: 26;
  --ds: 30;
}
.hour::after{
  /**/
  animation: hour calc(60s * 60 * 24) infinite steps(24);
  animation-delay: calc( -60s * 60 * var(--dh) );
}
.minitus::after{
  /**/
  animation: minitus calc(60s * 60) infinite steps(60);
  animation-delay: calc( -60s * var(--dm) );
}
.seconds::after{
  /**/
  animation: seconds 60s infinite steps(60);
  animation-delay: calc( -1s * var(--ds) );
}

Isn't it a little strange? Minutes changed only when it reached 30 seconds, half a minute late. The reason is that although the number of minutes is 26, we should also consider the movement of seconds. For example, in this case, the minute has actually gone half, which should be 26.5 (26 + 30 / 60), so we need to add the offset in the calculation. Let's get the real time through JS and fix the offset

const d = new Date()
const h = d.getHours();
const m = d.getMinutes();
const s = d.getSeconds();
document.body.style.setProperty('--ds', s)
document.body.style.setProperty('--dm', m + s/60)
document.body.style.setProperty('--dh', h + m/60 + s/3600)

This is normal

5, Flashing separator

In order to make the clock look more "dynamic", you can add flashing animation to the separator. The code is as follows

@keyframes shark {
  0%, 100%{
    opacity: 1;
  }
  50%{
    opacity: 0;
  }
}
.split{
  animation: shark 1s step-end infinite;
}

Now look at the final effect

The complete code is accessible CSS time (codepen.io)

6, To sum up

I didn't expect to realize a clock effect. So much CSS knowledge and skills are used. Let's briefly summarize it

  1. The essence of CSS implementation is endless cyclic CSS animation
  2. Flexible use of CSS calc calculation
  3. CSS counter can display CSS variables on the page through content
  4. The change of numbers can now be realized through CSS @property combined with animation
  5. The difference between hours, minutes and seconds lies in the different animation duration and animation starting point
  6. CSS automatic zero filling can refer to the previous article, which is implemented by decimal leading zero
  7. Time initialization is actually specifying the animation delay value
  8. When specifying the initial value, you also need to take into account their respective offsets, such as 19:30:30. At this time, the hour hand number is actually 30.5
  9. Flashing animation of separator

In fact, the whole implementation process is a process of continuous thinking and learning. For example, in order to realize the change of numbers, we must learn @ property correlation. In order to realize zero filling, we need to understand deeper counter correlation and various animations used. Finally, if you think it's good and helpful to you, you're welcome to like, collect and forward ❤❤❤

Tags: Front-end css3 html5 html css

Posted by bcoffin on Wed, 06 Apr 2022 07:03:06 +0300