72
头图

This article will comprehensively and meticulously sort out all aspects of CSS animation, explain the usage of each attribute and indicate the advanced usage, hoping to become a better tutorial from introductory to advanced.

CSS animation introduction and syntax

First, let's briefly introduce CSS animations.

The latest version of CSS animations is defined by the specification -- CSS Animations Level 1 .

CSS animations are used to effect transitions of elements from one CSS style configuration to another.

An animation consists of two parts: style rules that describe the animation and keyframes that specify the style of the animation's start, end, and midpoints.

In a nutshell, look at the following example:

div {
    animation: change 3s;
}

@keyframes change {
    0% {
        color: #f00;
    }
    100% {
        color: #000;
    }
}
  1. animation: move 1s part is the first part of the animation, which is used to describe the various rules of the animation;
  2. @keyframes move {} part is the second part of the animation, which is used to specify the keyframes of the animation start, end and intermediate point styles;

A CSS animation must be composed of the above two parts.

Syntax of CSS animations

Next, let's briefly look at the syntax of CSS animations.

To create an animation sequence, you need to use the animation property or its sub-properties. This property allows you to configure the animation time, duration and other animation details, but this property cannot configure the actual performance of the animation. The actual performance of the animation is implemented by the @keyframes rule.

The sub-properties of animation are:

  • animation-name: Specifies the keyframe name described by @keyframes.
  • animation-duration: Set the duration of one cycle of animation.
  • animation-delay: Set the delay, that is, the time from when the element is loaded until the animation sequence starts to execute.
  • animation-direction: Set whether the animation will run in reverse or return to the starting position after each run.
  • animation-iteration-count: Set the number of animation repetitions, you can specify infinite repetition of the animation
  • animation-play-state: Allows to pause and resume animations.
  • animation-timing-function: Set the animation speed, that is, by establishing an acceleration curve, set how the animation changes between keyframes.
  • animation-fill-mode: Specifies how to apply styles to the target element before and after the animation executes
  • @keyframes rules, of course, if an animation wants to run, it should also include @keyframes rules, which set animation keyframes internally

Among them, for an animation:

  • Mandatory : animation-name , animation-duration and @keyframes rules
  • Non must be item : animation-delay , animation-direction , animation-iteration-count , animation-play-state , animation-timing-function , animation-fill-mode , of course, is not to say that they are not set, but they have default values

A simple DEMO has been given above, just use the above DEMO and see the result:

This is a basic CSS animation. This article will start with each sub-property of animation and explore all aspects of CSS animation.

Animation-name / animation-duration Detailed explanation

Overall, the single animation-name and animation-duration do not have too many tricks, they are very easy to understand and put together.

First introduce animation-name , through animation-name , the CSS engine will find the corresponding @keyframes rule.

Of course, it is the same as the naming of CSS rules, and there are also some tricks. For example, he supports emoji expressions, so the animation-name name in the code can also be written like this:

div {
    animation: 😄 3s;
}

@keyframes 😄 {
    0% {
        color: #f00;
    }
    100% {
        color: #000;
    }
}

And animation-duration sets the duration of one cycle of the animation. In the above DEMO, the animation is set to last for 3s as a whole, which is also very easy to understand.

Detailed explanation of animation-delay

animation-delay is more interesting, it can set the animation delay, that is, the time from when the element is loaded until the animation sequence starts to execute.

A simple demo:

<div></div>
<div></div>
div {
    width: 100px;
    height: 100px;
    background: #000;
    animation-name: move;
    animation-duration: 2s;
}

div:nth-child(2) {
    animation-delay: 1s;
}
@keyframes move {
    0% {
        transform: translate(0);
    }
    100% {
        transform: translate(200px);
    }
}

Compare the following two animations, one with animation-delay added and one without, very intuitive:

The second div above, regarding the animation attribute, can also be abbreviated as animation: move 2s 1s , the first time value represents the duration, and the second time value represents the delay time.

animation-delay can be negative

The animation-delay is that it can be negative. That is to say, although the property name is animation delay time , but after using a negative number, the animation can be ahead of .

Suppose we want to implement such a loading animation effect:

There are several ideas:

  1. The position of the initial 3 balls is 120° apart, and they start to rotate at the same time, but the amount of code will be slightly more.
  2. Another way of thinking, the same animation, two of the 3 elements delay 1/3 of the entire animation, 2/3 of the time to start

The core pseudocode of Scheme 2 is as follows:

.item:nth-child(1) {
    animation: rotate 3s infinite linear;
}
.item:nth-child(2) {
    animation: rotate 3s infinite 1s linear;
}
.item:nth-child(3) {
    animation: rotate 3s infinite 2s linear;
}

However, in the first 2s of the animation, the other two elements will not move, and only after 2s, the whole animation is what we want:

At this time, we can change the delay time of the second and third elements to a negative value, so that the animation can be delayed by -1s and -2s , that is, 1s and 2s in advance:

.item:nth-child(1) {
    animation: rotate 3s infinite linear;
}
.item:nth-child(2) {
    animation: rotate 3s infinite -1s linear;
}
.item:nth-child(3) {
    animation: rotate 3s infinite -2s linear;
}

In this way, each element does not need to wait, it is directly in motion, and the element spacing is the result we want:

Build random effects with animation-duration and animation-delay

There is also an interesting little trick.

The same animation, we use random within a certain range animation-duration and a range of random animation-delay , can effectively build a more random animation effects, animation more natural.

I use this technique in the following two pure CSS animations:

  1. pure CSS to achieve Huawei charging animation :

纯 CSS 实现华为充电动画

  1. Pure CSS implements flame animation :

纯 CSS 实现火焰动画

Take pure CSS to realize Huawei charging animation as an example, and briefly explain it.

Carefully observe this part, the rising spheres one by one, throw away some fusion effects here, just focus on the rising spheres, it seems that there is no regularity at all:

Let's simulate, if we use 10 animation-duration and animation-delay , the core pseudocode:

<ul>
    <li></li>
    <!--共 10 个...--> 
    <li></li>
</ul>
ul {
    display: flex;
    flex-wrap: nowrap;
    gap: 5px;
}
li {
    background: #000;
    animation: move 3s infinite 1s linear;
}
@keyframes move {
    0% {
        transform: translate(0, 0);
    }
    100% {
        transform: translate(0, -100px);
    }
}

In this way, the movement of the ball will be uniform like this:

To make the movement of the ball appear very random, you only need to make animation-duration and animation-delay float within a certain range, and modify the CSS:

@for $i from 1 to 11 {
    li:nth-child(#{$i}) {
        animation-duration: #{random(2000)/1000 + 2}s;
        animation-delay: #{random(1000)/1000 + 1}s;
    }
}

We use the SASS loop and random() function to animation-duration within 2-4 seconds, and randomize animation-delay within 1-2 seconds. In this way, we can get very natural and different rising animation effects, which basically do not appear Repeating the picture, a good simulation of random effects:

CodePen Demo -- Random animation effect using range random animation-duration and animation-

animation-timing-function easing function

The easing function is very important in animation, it defines the rhythm of animation execution in each animation cycle.

Easing is mainly divided into two categories:

  1. cubic-bezier-timing-function cubic Bezier curve easing function
  2. step-timing-function step easing function (this translation is my own translation, it may be a bit strange)

Cubic Bezier Easing Function

First look at the cubic Bezier curve easing function . In CSS, some easing function keywords are supported.

/* Keyword values */
animation-timing-function: ease;  // 动画以低速开始,然后加快,在结束前变慢
animation-timing-function: ease-in;  // 动画以低速开始
animation-timing-function: ease-out; // 动画以低速结束
animation-timing-function: ease-in-out; // 动画以低速开始和结束
animation-timing-function: linear; // 匀速,动画从头到尾的速度是相同的

About the effect comparison between them:

In addition to these 5 keywords supported by CSS, we can also use the cubic-bezier() method to customize the cubic Bezier curve:

animation-timing-function: cubic-bezier(0.1, 0.7, 1.0, 0.1);

Here is a very useful website -- cubic-bezier for creating and debugging different bezier parameters.

The effect of cubic bezier easing on animation

Here's a very good example of the effect of easing functions on animations. Here we use pure CSS to achieve a clock effect. For the animation movement in it, if it is animation-timing-function: linear , the effect is as follows:

b

And if we replace the easing function into animation-timing-function: cubic-bezier(1,-0.21,.85,1.29) , its curve corresponds to the following:

The animation rhythm effect of the whole clock will become like this, completely different feeling:

CodePen Demo - Different effects of

For many lean animations, easing functions are actually considered in the design. I saw an article "Physics-based animation user experience design" a long time ago, but unfortunately I can't find the original text now. Some of the concepts conveyed are that animation is designed in terms of how it actually behaves in life.

For example, the linear easing will appear unnatural in some animations, because the uniform linear motion simulated by the program is difficult to achieve in real life due to the existence of air resistance. Therefore, it is difficult to establish a sense of trust for such a movement that the user rarely perceives. This kind of uniform linear motion is also something we need to avoid when designing dynamic effects.

Step easing function

Next, let's talk about the step easing function. In CSS animation-timing-function , it has the following expressions:

{
    /* Keyword values */
    animation-timing-function: step-start;
    animation-timing-function: step-end;

    /* Function values */
    animation-timing-function: steps(6, start)
    animation-timing-function: steps(4, end);
}

In CSS, the most used step easing function is to use it to achieve frame-by-frame animation. Suppose we have such a picture (the picture size is 1536 x 256 , the picture comes from the Internet):

It can be found that it is actually 6 states during the progress of a character, or it can be 6 frames. We animation-timing-function: steps(6) to concatenate them with a CSS animation. The code is very simple:

<div class="box"></div>
.box {
  width: 256px;
  height: 256px;
  background: url('https://github.com/iamalperen/playground/blob/main/SpriteSheetAnimation/sprite.png?raw=true');
  animation: sprite .6s steps(6, end) infinite;
}
@keyframes sprite {
  0% { 
    background-position: 0 0;
  }
  100% { 
    background-position: -1536px 0;
  }
}

To briefly explain the above code, we must first know that it is exactly 256 x 6 = 1536 , so the above picture can actually be divided into 6 segments:

  1. We set a div with a size of 256px , and gave this div a animation: sprite .6s steps(6) infinite animation;
  2. Among them, steps(6) means that the set @keyframes animation is divided into 6 times (6 frames) for execution, and the overall animation time is 0.6s , so the pause time of each frame is 0.1s ;
  3. The animation effect is from background-position: 0 0 to background-position: -1536px 0 . Since the above CSS code does not set background-repeat , in fact, background-position: 0 0 is equivalent to background-position: -1536px 0 , that is, the picture advances one round during the entire animation process, but each frame stops at the characteristic place, A total of 6 frames;

Draw the above steps 1, 2, 3, and 3 on the diagram for a simple illustration:

As can be seen from the above figure, in fact, during the animation process, the value of background-position background-position: 0 0 , background-position: -256px 0 , background-position: -512px 0 and so on until background-position: -1536px 0 . Due to the characteristics of the repeat of the background, it just returns to the original point, and a new round starts again. animation.

So, the whole animation will be like this, each frame stays for 0.1s and then switches to the next frame (note that this is an infinite loop animation),:

here for the complete code -- 161e0e03969a79 CodePen Demo -- Sprite Animation with steps()

animation-duration The effect of animation length on animation

Insert a small chapter here, animation-duration The influence of animation length on animation is also very obvious.

On the basis of the above code, we modify animation-duration to shorten the time of each frame to make the effect of walking become the effect of running. Similarly, the dwell time of each frame can also be increased. Make each step slow, as if you were walking.

It should be pointed out that each frame mentioned above is not the same concept as each frame of FPS in the browser rendering process.

Take a look at the effect, set different effects of animation-duration (here is 0.6s -> 0.2s), the GIF screen recording lost some key frames, the actual effect will be better:

Of course, in steps() , there is also steps(6, start) and steps(6, end) , that is, the difference between the keywords start and end . For the above infinite animation, it is basically negligible. It mainly controls the start and duration of the first frame of the animation. It is a relatively small knowledge point, but it takes a long time to explain it, and it is limited to the content of this article. , which is not expanded here, the reader can understand it by himself.

Comparison of tween animation and frame-by-frame animation interpretation of the same animation effect

The above cubic Bezier curve easing and step easing are actually the corresponding tween animation and frame-by-frame animation.

For the same animation, sometimes both kinds of easing are applicable. We need specific analysis and selection when we use it.

Suppose we implement a graph like this with CSS:

Now I want to use this graphic to make a Loading effect. If I use a tween animation, that is, a cubic Bezier curve easing, and let it rotate, the effect is very general:

.g-container{
    animation: rotate 2s linear infinite;
}
@keyframes rotate {
    0% {
        transform: rotate(0);
    }
    100% {
        transform: rotate(360deg);
    }
}

The animation effect is as follows:

But if here, we replace the tween animation with frame-by-frame animation, because there are 20 points, so set it to steps(20), and then look at the effect, you will get a completely different feeling:

.g-container{
    animation: rotate 2s steps(20) infinite;
}
@keyframes rotate {
    0% {
        transform: rotate(0);
    }
    100% {
        transform: rotate(360deg);
    }
}

The animation effect is as follows:

The entire loading circle seems to be rotating, but in fact, only 20 frames of key frames are switching, and the overall effect feels more suitable for the effect of Loading.

Therefore, it is necessary to master both animation effects, and try flexibly in actual use, and choose the more suitable one.

The complete code for the above DEMO effect: CodePen Demo -- Scale Loading steps vs linear

animation-play-state

Next, let's talk about animation-play-state , which, as the name suggests, controls the state of the animation -- running or pausing. Similar to video player start and pause. It is one of the limited means of controlling the animation state in CSS animation.

It has only two values (running by default):

{
    animation-play-state: paused | running;
}

It is also very simple to use. Look at the following example. When we hover the button, we realize the pause of the animation:

<div class="btn stop">stop</div>
<div class="animation"></div>
.animation {
    width: 100px;
    height: 100px;
    background: deeppink;
    animation: move 2s linear infinite alternate;
}

@keyframes move {
    100% {
        transform: translate(100px, 0);
    }
}

.stop:hover ~ .animation {
    animation-play-state: paused;
}

A simple CSS animation, but when we hover the button, add animation-play-state: paused to the animated element:

animation-play-state trick, pause by default, click to run

Normally, it is very simple to animation-play-state: paused in the normal way.

However, if we want to create some interesting CSS animations, we should do the opposite.

We all know that under normal circumstances, the animation should be in the running state, then if we set the default state of some animations to pause, only when the mouse is clicked or hover, will it be set to animation-play-state: running , so that we can get a lot of interesting CSS effects .

Let's see an example of pouring wine. This is a pure CSS animation, but by default, the animation is in animation-play-state: paused , that is, in a paused state. Only when the mouse clicks on the glass, animation-play-state: running is set to make the wine fall. Using animation-play-state a Very interesting interaction effects:

The complete demo can be found here: CodePen Demo -- CSS Beer!

We can see this technique in many creative interactive animations on the Web.

  1. After the page is rendered, without any operation, the animation will not start. Only when the mouse performs click on the element, by triggering the :active pseudo-class effect of the animation-play-state: running , the animation starts;
  2. When the animation progresses to any moment, the mouse stops clicking and the pseudo-class disappears, the animation stops;

animation-fill-mode controls the state of the element at various stages

The next property is animation-fill-mode , which many people mistakenly think is just used to control whether the element resets after the animation ends. This is actually inaccurate and incomplete.

Take a look at its value:

{
    // 默认值,当动画未执行时,动画将不会将任何样式应用于目标,而是使用赋予给该元素的 CSS 规则来显示该元素的状态
    animation-fill-mode: none;
    // 动画将在应用于目标时立即应用第一个关键帧中定义的值,并在 `animation-delay` 期间保留此值,
    animation-fill-mode: backwards; 
    // 目标将保留由执行期间遇到的最后一个关键帧计算值。 最后一个关键帧取决于 `animation-direction` 和 `animation-iteration-count`
    animation-fill-mode: forwards;    
    // 动画将遵循 `forwards` 和 `backwards` 的规则,从而在两个方向上扩展动画属性
    animation-fill-mode: both; 
}

For animation-fill-mode , I saw 4 good interpretation diagrams in a question and answer on Segment Fault ( SF - How to understand animation-fill-mode ), here are borrowed:

Suppose the HTML is as follows:

<div class="box"></div>

The CSS is as follows:

.box{
    transform: translateY(0);
}
.box.on{
    animation: move 1s;
}

@keyframes move{
    from{transform: translateY(-50px)}
    to  {transform: translateY( 50px)}
}

Use images to represent translateY value and time relationship:

  • The horizontal axis is a time , represents the start time of the animation is 0, that is, the box plus the name of the class time on the horizontal axis represents a grid 0.5s
  • The vertical axis represents the value of translateY translateY , and one grid on the vertical axis represents 50px
  1. animation-fill-mode: none shown in the figure:

To sum it up in one sentence, outside the animation time, the style of the element is only limited by its CSS rules, regardless of the keyframe definitions in @keyframes.

  1. animation-fill-mode: backwards shown in the figure:

In one sentence, the style of the element before the animation starts (including the non-triggered animation stage and animation-delay ) is the first frame of the animation, and the style after the animation is restored to the style set by the CSS rules.

  1. animation-fill-mode: forwards shown in the figure:

In one sentence, the style of the element before the animation starts is the style set by the CSS rules, and the style after the animation ends is calculated from the last keyframe encountered during execution (that is, stopped at the last frame).

  1. animation-fill-mode: both shown in the figure:

In one sentence, it combines the animation-fill-mode: backwards and animation-fill-mode: forwards . The style before the animation starts is the first frame when the animation is running, and stops at the last frame after the animation ends.

animation-iteration-count/animation-direction animation iteration count and direction

Speaking of animation-fill-mode , we can talk about these two well-understood attributes - animation-iteration-count and animation-direction

  • animation-iteration-count controls the number of times the animation runs, it can be a number or infinite , note that the number can be a decimal
  • animation-direction Control the direction of the animation, forward, reverse, forward alternate and reverse alternate

When talking about animation-fill-mode above, I used the first frame animation run instead of the first frame defined in @keyframes, because the actual state of the first and last frames of the animation is also affected by the animation animation-iteration-count of running directions animation-direction and 061e0e0396a26d.

In CSS animation, animation-iteration-count and animation-direction jointly determine the state of the first and last frames when the animation is running.

  1. The first frame of the animation run is determined animation-direction
  2. The last frame of the animation run is determined animation-iteration-count and animation-direction

The last frame of the animation is the final state of the animation, and we can use animation-fill-mode: forwards make the animation stay at this frame after the end, which is easy to animation-fill-mode: backwards and animation-direction Briefly explain.

Setting a 100px x 100px slider, a 400px x 100px vessel, which code is as follows:

<div class="g-father">
    <div class="g-box"></div>
</div>
.g-father {
    width: 400px;
    height: 100px;
    border: 1px solid #000;
}
.g-box {
    width: 100px;
    height: 100px;
    background: #333;
}

The performance is as follows:

Then, animation , under the animation-iteration-count and animation-direction , the initial and end states of the animation are different.

animation-fill-mode: backwards is set, the state of the element before the animation begins is determined animation-direction

.g-box {
    ...
    animation: move 4s linear;
    animation-play-state: paused;
    transform: translate(0, 0);
}
@keyframes move {
    0% {
        transform: translate(100px, 0);
    }
    100% {
        transform: translate(300px, 0);
    }
}

Note that in the CSS rule here, the element does not have a displacement of transform: translate(0, 0) , and in the animation, the first key frame and the last key translateX are 100px and 300px , respectively, with different animation-direction as follows.

The following figure assumes that we set the animation to be paused by default -- animation-play-state: paused , then the state of the animation before it starts is:

Divide and conquer animation

After talking about each property, let's take a look at some details of the animation usage process.

Watch this animation:

<div></div>
div {
    width: 100px;
    height: 100px;
    background: #000;
    animation: combine 2s;
}
@keyframes combine {
    100% {
        transform: translate(0, 150px);
        opacity: 0;
    }
}

Here we implement a falling animation of a div block, which changes the transparency while falling:

For such an animation of multiple property changes, it is actually equivalent to:

div {
    animation: falldown 2s, fadeIn 2s;
}

@keyframes falldown {
    100% {
        transform: translate(0, 150px);
    }
}
@keyframes fadeIn {
    100% {
        opacity: 0;
    }
}

In CSS animation rules, animation can receive multiple animations. The purpose of this is not only for reuse , but also for divide and conquer . We can have more accurate animations for each attribute level control.

keyframes rule settings

We can often see the following two CSS @keyframes settings in various CSS codes:

  1. use percentage

    @keyframes fadeIn {
     0% {
         opacity: 1;
     }
     100% {
         opacity: 0;
     }
    }
  2. Use from and to

    @keyframes fadeIn {
     from {
         opacity: 1;
     }
     to {
         opacity: 0;
     }
    }

In the definition of CSS animation @keyframes from equivalent to 0% , and to equivalent to 100% .

Of course, when our key frames are more than 2 frames, it is more recommended to use the percentage definition method.

In addition, when the value of the starting frame of the animation equivalent to the CSS rules given and there is no set animation-fill-mode , 0% and from the frame can be deleted.

High priority of animation state

I once talked about an interesting CSS phenomenon in this article -- Deep Understanding of Cascading in CSS (Cascading Style Sheets)

This is also a misunderstanding of CSS priorities for many people, In CSS, the priority also needs to consider the cascading (cascading) order of .

Which value is used depends on the style's priority only if the stacking order is equal.

So what is the cascading order?

According to CSS Cascading 4 latest standard:

CSS Cascading and Inheritance Level 5(Current Work)

The priority of the cascading order declared under the current specification defined is as follows (the higher the priority, the higher the priority, and the following rules are in ascending order):

  • Normal user agent declarations
  • Normal user declarations
  • Normal author declarations
  • Animation declarations
  • Important author declarations
  • Important user declarations
  • Important user agent declarations
  • Transition declarations

Simply translate:

According to the above algorithm, it is probably like this:

The style of each frame during the transition animation > the !important style set by the user agent, user, and page author > the style priority of each frame during the animation process > the normal style of the page author, user, and user agent.

However, after testing with multiple browsers, this is not actually the case. (embarrassed)

For example, we can use this feature to override the !important style in the inline style:

<p class="txt" style="color:red!important">123456789</p>
.txt {
    animation: colorGreen 2s infinite;
}
@keyframes colorGreen {
    0%,
    100% {
        color: green;
    }
}

In the Safari browser, the color of the above DEMO text is green , that is to say, the style in the animation state can override the !important style in the inline style, which belongs to the highest priority style. Infinite animation, or animation-fill-mode: forwards !important style in the inline style that should have been a very, very high priority.

I can get the same result in Chrome two years ago, but as of today (2022-01-10), the latest version of Chrome no longer supports the feature that the keyframe style priority overrides the inline style !important during animation.

For different browsers, interested students can use my demo to try by themselves, CodePen Demo - the priority of CSS Animation

Optimization of CSS animations

This is also a key point that many people are very concerned about.

My CSS animation is stuck, how can I optimize it?

Animated elements generate independent GraphicsLayer, forced to start GPU acceleration

CSS animation very slow, in fact, is a description of the phenomenon, its essence is in fact the animation process, browser to refresh the page rendering frame rate is too low . Generally speaking, the current refresh rate of most browsers is 60 times/second, so generally speaking, the animation effect is better when the FPS is 60 frame/s, that is, the consumption time per frame is 16.67ms.

When the page is in animation change, when the frame rate is lower than a certain value, we feel the page is stuck.

The reason for the low frame rate is that the browser processes too many things in one frame, exceeding 16.67ms. To optimize the time of each frame, it is necessary to completely know what the browser does in each frame. This again involves the old-fashioned browser rendering page.

To this day, although the rendering processes of different browsers are not exactly the same, they are basically the same, basically:

Simplified is this picture:

You can see these two pictures in many different articles.

Returning to the main point of this article, a large part of the overhead of web animation is layer repainting, and layer-based composite models have a profound impact on rendering performance. When no drawing is required, the cost of compositing operations is negligible, so when trying to debug rendering performance issues, the first goal is to avoid layer redraws. Then this performance optimization animation to provide direction, reduce redraw the return element .

Among them, how to reduce the reflow and redraw of the page, here we will use the GPU acceleration that we often say.

The essence of GPU acceleration is to reduce the reflow and repaint in the process of rendering each frame of the page by the browser. The fundamental is to make the elements that need to be animated to generate their own GraphicsLayer .

When a browser renders a page, it uses many intermediate representations that are not exposed to the developer, the most important of which is the layer.

In Chrome, there are different types of layers: RenderLayer (responsible for the DOM subtree), GraphicsLayer (responsible for the RenderLayer subtree).

GraphicsLayer , which is very important for our web animations, normally Chrome will paint the contents of a layer into a bitmap before uploading it to the GPU as a texture. If the content does not change, then there is no need to repaint the layer.

When the element generates its own GraphicsLayer, during the animation process, Chrome will not always redraw the entire layer, it will try to intelligently redraw the part of the DOM that fails, that is, the part where the animation occurs. Before Composite, The page is in a layered state. With the help of the GPU, the browser only redraws the element layer that has generated its own independent GraphicsLayer in each frame. In this way, the cost of rearranging and redrawing the entire page is greatly reduced and the page rendering is improved. s efficiency.

Therefore, the first criterion for optimization of CSS animation (similar to Web animation) is that allows the elements that need to be animated to generate their own independent GraphicsLayer, forcing the start of GPU acceleration , and we need to know that the essence of GPU acceleration is to use the It generates its own independent GraphicsLayer, which reduces the overhead of redrawing and reflowing the page during the rendering process.

Of course, there are many ways to generate your own independent GraphicsLayer, not only the transform3d api. In CSS, including but not limited to (find a lot of documents, not very comprehensive, you need to try one by one, by turning on Chrome's Layer border option):

  • 3D or perspective transform (perspective, transform) CSS properties
  • <video> element using accelerated video decoding
  • <canvas> element with 3D (WebGL) context or accelerated 2D context
  • Hybrid plugins (like Flash)
  • Animate your opacity with CSS or use an animated transform element
  • Elements with accelerated CSS filters
  • An element has a descendant node that contains a composite layer (in other words, an element has a child element that is in its own layer)
  • The element has a lower z-index sibling that contains a composite layer (in other words the element is rendered on top of the composite layer)

For the above-mentioned large paragraph of very convoluted content, you can take a look at these articles:

In addition to the above guidelines, here are some suggestions for improving the performance of CSS animations:

Reduce consumption performance style

Different styles are different in terms of performance cost, changing some properties is more expensive than changing others and therefore more likely to stutter animations.

For example, changing the element's box-shadow would require a much more expensive drawing operation than changing the element's text color. box-shadow attribute is very performance-intensive from a rendering perspective, because their rendering code takes too long to execute compared to other styles. That said, if a performance-heavy style requires frequent redraws, you'll have performance issues.

Similar to CSS 3D transform, mix-blend-mode , filter , these styles consume more performance than other simple operations. We should try to reduce the frequency of its use or find alternatives in the animation process as much as possible.

Of course, there is no constant, styles that perform poorly today may be optimized tomorrow, and there are differences between browsers.

So the key is that we need to use development tools to identify the performance bottleneck for each case of freeze, and then try to reduce the workload of the browser. It is very important to learn about the Performance panel and other rendering-related panels of the Chrome DevTools, but of course this is not the focus of this article. You can explore on your own.

Use will-change to improve the rendering performance of page scrolling, animation, etc.

will-change provides a way for web developers to tell the browser what changes will be made to the element, so that the browser can prepare for optimizations in advance of the actual changes to the element properties. This optimization can prepare a part of the complex calculation work in advance, making the page more responsive and responsive.

It is worth noting that it is not very easy to use this property well:

  • Don't apply will-change to too many elements: browsers already try to optimize everything they can. There are some more powerful optimizations that, if combined with will-change, may consume a lot of machine resources, and if overused, may cause pages to respond slowly or consume a lot of resources.
  • Use sparingly: Often, when an element is restored to its original state, the browser throws away any optimizations it did before. will-change attribute is explicitly declared directly in the stylesheet, it means that the target element may change frequently, and the browser will save the optimization work longer than before. So the best practice is to switch the value of will-change via script before and after the element changes.
  • Don't apply will-change optimizations prematurely: If your page has no issues with performance, don't add the will-change attribute to squeeze a tiny bit of speed. will-change was originally designed as a last resort to try to solve existing performance problems. It should not be used to prevent performance issues. Excessive use of will-change can result in a large memory footprint and can result in a more complex rendering process as the browser tries to prepare for possible changes. This can lead to more serious performance issues.
  • Give it enough time to work: This property is used by the page developer to inform the browser which properties may change. The browser can then choose to do some optimization work ahead of time before the change happens. So it's important to give the browser some time to actually do these optimizations. When using it, you need to try to find some methods to know the possible changes of the element in advance, and then add the will-change attribute to it.

Some people say that will-change is a good medicine, and some people say that it is a poison. When using it, you can test it more.

At last

Well, this article describes some of the more important, worth mentioning, and noteworthy points of CSS animation from various aspects, from shallow to deep. Of course, there are many places that stop at the end, or are not fully expanded due to space limitations. Many details still require readers to further read the specifications or try to verify it by themselves, so as to realize the truth through practice, and it will be superficial on paper.

OK, this is the end of this article, I hope this article will help you :)

If you want to get the most interesting CSS information, don't miss my account -- 161e0e0396acf6 iCSS front-end anecdote 😄

More wonderful CSS technical articles are summarized in my Github -- iCSS , which will be updated continuously. Welcome to click a star to subscribe to the collection.

If you have any questions or suggestions, you can communicate more. Original articles are limited in writing and knowledge. If there are any inaccuracies in the article, please let me know.


chokcoco
12.3k 声望18.5k 粉丝