The last blog post [ setTimeout is not on time, CSS realizes the timer function accurately ] finally mentioned the way to realize the timer through CSS animation.
This article describes in detail how to fully realize the clock effect through CSS, which is also a content of the team's 21-year patent (patent publication number: CN114003087A).
This invention patent mainly solves the problem of inaccurate clock realized by javascript under the big screen. Timing is done through CSS animations to avoid synchronous blocking issues.
Pre-knowledge
pseudo element
Pseudo-elements allow you to modify styles for specific parts of selected elements.
::after
Used to create a pseudo-element as the last child of the selected element. Attributes are usually used to content
add decorative content to the element. This virtual element is an inline element by default.
Pseudo elements :before
and :after
added content are inline elements by default
- Pseudo elements do not belong to the document , so js cannot manipulate it
- The pseudo-element is part of the main element, so clicking on the pseudo-element triggers the click event of the main element
- Only block-level elements can have :before, :after, which is actually inappropriate. Most row-level elements can also set pseudo-elements, but replaceable elements like img, because their appearance and size are determined by external resources, then if the external resources are correct Loading will replace its internal content, and the pseudo-element will also be replaced at this time, but when the external resource fails to load, the set pseudo-element can work.
example
a::after {
content: "→";
}
data attribute data-*
HTML5 is designed to be extensible, it is intended that data should be associated with specific elements, but it does not require any definition. data-*
Allows us to store additional information in HTML elements within the standard without using something like classList.
attr()
A CSS expression attr()
is used to obtain an HTML attribute value of the selected element and use it for its style. It can also be used on pseudo-elements, the attribute value takes the element the pseudo-element is attached to.
attr()
In theory, it can be used for all CSS properties, but currently only the content property of pseudo-elements is supported. Other properties and advanced features are currently experimental
example
Combining with data attributes, the corresponding effect display can be well realized.
hover to <a>
the tag to display the corresponding data-hover content
<style>
a:hover::after {
content: attr(data-hover);
}
</style>
<body>
<a href="javascript:void(0);" data-hover="hover展示内容">hover</a>
</body>
css animation
The animation attribute is a shorthand attribute form of the animation-name, animation-duration, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, animation-fill-mode, and animation-play-state attributes.
Attributes | illustrate | example |
---|---|---|
animation-name |
Specifies a sequence of animations to apply | animation1,animation2 |
animation-duration |
Specify the duration of an animation cycle in s or ms | 60s |
animation-timing-function |
The cadence to execute in each animation cycle | ease 、linear 、steps(60) |
animation-delay |
Define when the animation starts, in s or ms | 100ms |
animation-iteration-count |
Defines the number of times the animation will run before ending | infinite (unlimited times),3 |
animation-direction |
Indicates whether the animation plays in reverse | normal 、alternate 、reverse |
animation-fill-mode |
Sets how CSS animations apply styles to their targets before and after execution | forwards 、backwards |
animation-play-state |
Defines whether an animation is running or paused | running 、paused |
steps(number_of_steps, direction)
: Defines a step function that divides the domain of output values equidistantly.
example
The duration of the animation cycle is 10s, divided into 10 steps equidistantly, the timer is executed once per second, and the loop is executed infinitely.
animation: timer 10s infinite steps(10) forwards;
translate
transform: translate(x, y)
/ translate: x y;
translation transform.
example
a:hover {
translate: 200px 50px;
/*等价于*/
transform: translate(200px, 50px);
}
Implementation ideas
Step 1: Define the DOM
DOM defines hours, minutes, and seconds, and binds related data through data attributes for hours, minutes, and secondsdata-*
<!-- 时 -->
<div class="card">
<div class="card-hours"> <!-- 见步骤四其作用 -->
<div class="hours" data-hours="18 19 20 21 22 23 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17"></div>
</div>
</div>
<div class="card">:</div>
<!-- 分 -->
<div class="card">
<div class="card-minutes"> <!-- 见步骤四其作用 -->
<div class="minutes"
data-minutes="58 59 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57">
</div>
</div>
</div>
<div class="card">:</div>
<!-- 秒 -->
<div class="card">
<div class="seconds"
data-seconds="50 51 52 53 54 55 56 57 58 59 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49">
</div>
</div>
About data-hours
, data-minutes
, data-seconds
data are initialized with the current time (dynamic form). For the above example, the initial time is: 18:58:50
For the above, for minutes and hours, there is an additional layer of DOM, <div class="card-hours">
and <div class="card-minutes">
subsequent interpretation ( see step 4 ).
Step 2: Display the basic definition of the area
Here for: unified setting of hour, minute and second.
Set a fixed size font-size
to ensure that only one number can be displayed in each line; at the same time, specify line-height
to ensure that only one number is displayed in the visible area. (preparing for the follow-up animation)
body {
font-size: 48px;
}
.card {
display: inline-block;
height: 68px;
overflow: hidden;
}
.hours, .minutes, .seconds {
width: 68px;
line-height: 68px;
}
font-size
,line-height
attribute, with inheritance, runs through the entire web pagefont-size
,line-height
attributes, and font width have no necessary conversion relationship; if you want the font to be of equal width, you need to use equal width fonts (such as: Consolas, Monaco, monospace)
Step 3: Realize "seconds"
Each cycle is 60s, divided into 60 equidistant parts (sexagesimal), each part is 1s, and then the next value is displayed translate
by .
.seconds:after {
display: block;
content: attr(data-seconds);
animation: counter 60s steps(60) infinite forwards;
}
@keyframes counter {
from {
translate: 0 0;
}
to {
translate: 0 -100%;
}
}
Step 4: Realize "minutes and hours"
For minutes and hours, the logic of scrolling display is the same as that of seconds, but the number of cuts and unit time need to be determined according to the actual situation.
- Minutes: equidistant 60 parts (sexadecimal), a cycle 60 ∗ 60 = 3600 60 * 60 = 360060∗60=3600
- Hours: 24 equidistant (24 hexadecimal), one cycle $ 24 * 60 * 60 = 86400$
.minutes:after {
display: block;
content: attr(data-minutes);
animation: counter 3600s steps(60) infinite forwards;
animation-delay: 10s; /* 延后执行 */
}
.hours:after {
display: block;
content: attr(data-hours);
animation: counter 86400s infinite steps(24) forwards;
animation-delay: 70s; /* 延后执行 */
}
The difference between minutes, hours and seconds is that the probability of the first base is not 60 or 24.
Explain with the above example: the current second is 50, and after another 10s (calculation method: $ 60 - 50 ), the minute should become 59; similarly, after another 70 seconds (calculation method: ), the minute should become 59; Similarly, after another 70s (calculation method:), the minute should become 59 ; similarly, after another 70 s (calculation method: 3600 - 58*60 - 50 $), the hour should become 19.
Therefore, the above animation-delay
is to let the fixed-period animation start later, and the waiting time is calculated based on the initial time.
animation-delay
Specifies the amount of time to wait between applying an animation and before the element starts animating
Step one, mentioned in <div class="card-hours">
, <div class="card-minutes">
is for this.
.card-minutes {
height: 136px;
overflow: hidden;
/* 60-pastSeconds */
animation: delay-counter 10s steps(1) 1 forwards;
}
.card-hours {
height: 136px;
overflow: hidden;
/* 3600-pastMinutes*60-pastSeconds */
animation: delay-counter 70s steps(1) 1 forwards;
}
@keyframes delay-counter {
from {
translate: 0 0;
}
to {
translate: 0 -50%;
}
}
The above animation is executed only once (initialization)
Summarize
CSS animations work well, even on low performance systems. Rendering engines use frame skipping or other techniques to keep animations as smooth as possible.
At the same time, the animation also provides corresponding events in each execution stage, which will not be expanded here for the time being. Those who have appeals can check the relevant MDN AnimationEvent .