A brief discussion on CSS3 animation jamming solutions

A brief discussion on CSS3 animation jamming solutions

Why is it stuck?

There is a premise that must be mentioned. Front-end developers all know that the browser runs in a single thread. But we need to clarify the following concepts: single thread, main thread and synthesis thread.

Although the browser executes JS in a single thread (note, it is execution, not that the browser has only one thread, but running), in fact, the browser has two important execution threads, which work together to render a web page: the main thread and the synthesis thread.

In general, the main thread is responsible for: running JavaScript; calculating the CSS styles of HTML elements; layout of the page; drawing elements into one or more bitmaps; and handing these bitmaps to the synthesis thread.

Accordingly, the composition thread is responsible for: drawing the bitmap to the screen through the GPU; notifying the main thread to update the bitmap of the visible or soon-to-be-visible part of the page; calculating which part of the page is visible; calculating which part is about to become visible when you scroll the page; and moving elements of the corresponding position into the visible area when you scroll the page.

So why does the animation freeze?

The reason is that the scheduling of the main thread and the synthesis thread is unreasonable.

Let's talk about the reasons for unreasonable scheduling in detail:

When using height, width, margin, and padding as transition values, the browser main thread will have a heavy workload. For example, when rendering from margin-left: -20px to margin-left: 0, the main thread needs to calculate the styles of margin-left: -19px, margin-left: -18px, all the way to margin-left: 0. Moreover, each time the main thread calculates the style, the synthesis process needs to draw it to the GPU and then render it to the screen. A total of 20 main thread renderings and 20 synthesis thread renderings are performed, 20+20 times, for a total of 40 calculations.

The rendering process of the main thread can refer to the process of browser rendering web pages:

  • Creating a Document Object Model (DOM) using HTML
  • Creating the CSS Object Model (CSSOM) using CSS
  • Executing scripts based on DOM and CSSOM
  • Merge DOM and CSSOM to form a render tree
  • Use the render tree to layout all elements
  • Paint all elements

That is to say, the main thread needs to execute the calculations of the four stages of Scripts, Render Tree, Layout and Paint every time.

And if transform is used, for example, tranform:translate(-20px,0) to transform:translate(0,0), the main thread only needs to perform one tranform:translate(-20px,0) to transform:translate(0,0), and then the synthesis thread will convert -20px to 0px once, so the total calculation is 1+20.

Some people may say that this is only an improvement of 19 times, what good performance improvement is there?

Assume 10ms at a time.

This reduces the time consumption by about 190ms.

Some people may say, it’s crap, only 190ms, it doesn’t matter.

So what if margin-left is from -200px to 0, 10ms at a time, 10ms

199≈2s.

Some people will say, it’s trash, it’s only 2s, it doesn’t matter.

Did you forget about single threading?

2s=6s, which means a performance improvement of 6s.

Since the data is guesswork, its authenticity is not considered for the time being.

In order to enhance the persuasiveness of this article, I will use an example to prove my point. Let's take a look at it together.

In the front end, animation is used to implement the home page animation transition in the H5 page. It is a very simple effect. A customer service avatar is loaded on the home page, first enlarged, stayed for 700ms, and then shrunk to the top. The code is as follows:

<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=1" >
  <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js"></script>
  <title>Homepage loading animation</title>
  <head>
    <style>
      .welcome-main{
        display: none;        
        padding-bottom: 40px;      
      }
      .top-info{        
        width: 100%;        
        position: absolute;        
        left: 0;        
        top: 93px;      
      }
      .wec-img{
        width: 175px;        
        height: 175px;        
        position: relative;        
        padding: 23px;        
        box-sizing: border-box;        
        margin: 0 auto;      
       }
      .wec-img:before{        
        content: '';        
        position: absolute;        
        left: 0;        
        top: 0;        
        width: 100%;        
        height: 100%;        
        background: url("./images/kf-welcome-loading.jpg");        
        background-size: 100%;      
       }
      .wec-img .img-con{
        width: 100%;        
        height: 100%;        
        border-radius: 50%;        
        /*box-sizing: border-box;*/
        background: url("./images/kf_1.jpg");        
        background-size: 100%;        
        padding: 1px;      
      }
      .wec-img .img-con img{
        width: 100%;        
        height: 100%;        
        border-radius: 50%;      
      }
      .loaded .wec-img{
        -webkit-transform-origin: center top;      
      }        
      .loading.welcome-main{
        display: block;
      }
      .loading .wec-img{
        -webkit-animation:fadeIn .3s ease both;
      }
      .loading .wec-img:before{
        -webkit-animation:rotate .6s .2s linear both;      
      }
      .loaded .top-info{
        -webkit-animation:mainpadding 1s 0s ease both;      
      }
      .loaded .wec-img{
        -webkit-animation:imgSmall 1s 0s ease both; }
      @-webkit-keyframes mainpadding{
        0%{-webkit-transform:translateY(0)  
      }
        100%{-webkit-transform:translateY(-87px)   
        }
      }      
      @-webkit-keyframes imgSmall{
        0%{
          width: 175px;          
          height: 175px;          
          padding: 23px;        
        }
        100%{          
          width: 60px;          
          height: 60px;          
          padding: 0;        
        }
      }      
      @-webkit-keyframes fadeIn{
        0%{opacity:0;-webkit-transform:scale(.3)}
        100%{opacity:1;-webkit-transform:scale(1)}
      }      
      @-webkit-keyframes rotate{
        0%{opacity:0;-webkit-transform:rotate(0deg);}
        50%{opacity:1;-webkit-transform:rotate(180deg);}
        100%{opacity:0;-webkit-transform:rotate(360deg);}
      }     
      </style>
    <body>
      <div class="welcome-main">
        <div class="top-info">
          <div class="wec-img"><p class="img-con"><img src="" alt=""></p></div>
        </div>
      </div>
      <script>
        $('.welcome-main').addClass('loading');
        setTimeout(function(){
          $('.hi.fst').removeClass('loading');
          $('.welcome-main').addClass('loaded');
        },700);
      </script>
    </body>
  </html>

The test was ok on Chrome, but when submitting the test to QA, it was found that some models, such as Huawei (system 4.2) and OPPO (system 5.1), had lags.

I was puzzled, so I referred to the article "In-depth understanding of browser performance issues of CSS animations and transitions" and changed the animation element in the image scaling to transform, as follows

@-webkit-keyframes imgSmall{
 0%{
   -webkit-transform:scale(1);
 }
 100%{
   -webkit-transform:scale(.465);
 }
}

Sure enough, the lag problem was solved.

The article In-depth understanding of the browser performance issues of CSS animations and transitions explains that modern browsers usually have two important execution threads that work together to render a web page: the main thread and the synthesis thread.

In general, the main thread is responsible for: running JavaScript; calculating the CSS styles of HTML elements; layout of the page; drawing elements into one or more bitmaps; and handing these bitmaps to the synthesis thread.

Accordingly, the composition thread is responsible for: drawing the bitmap to the screen through the GPU; notifying the main thread to update the bitmap of the visible or soon-to-be-visible part of the page; calculating which part of the page is visible; calculating which part is about to become visible when you scroll the page; and moving elements of the corresponding position into the visible area when you scroll the page.

Suppose we want an element's height to change from 100 px to 200 px, like this:

div {
  height: 100px;
  transition: height 1s linear;
}
  
div:hover {
  height: 200px;
}

The main thread and the synthesis thread will perform corresponding operations according to the following flowchart. Note that operations in the orange box may be time-consuming, while operations in the blue box are faster.

And use transform:scale to achieve

div {
  transform: scale(0.5);
  transition: transform 1s linear;
}
  
div:hover {
  transform: scale(1.0);
}

The process is as follows:

That is, using transform, the browser only needs to generate the bitmap of the element once and submit it to the GPU for processing when the animation starts. After that, the browser does not need to do any layout, drawing, or bitmap submission operations. Thus, the browser can take full advantage of the GPU to quickly draw the bitmap in different positions, perform rotation or scaling.

In order to confirm this theory from an order of magnitude, I opened Chrome's Timeline to view the page FPS

Among them, when using height as an animation element, the FPS during the switching process is only 44. We know that 60 frames per second is the most suitable interaction for the human eye. If it is less than 60, the human eye can clearly feel it, which is why there is a freeze.

The time spent on rendering and painting is as follows:

Let's look at using transform:scale

FPS reached 66, and rendering and painting time was reduced by 3 times.

So far the problem was solved. A few days later, I saw an article about how to solve the "stuttering" problem of Chrome animations. I found that I could also optimize the animations by turning on hardware acceleration, so I tried it again.

webkit-transform: translate3d(0,0,0);
-moz-transform: translate3d(0,0,0);
-ms-transform: translate3d(0,0,0);
-o-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);

Something amazing happened, the FPS reached 72:

Summary of solutions to CSS3 animation jams

Try to use transform as animation, avoid using height, width, margin, padding, etc.

When the requirements are higher, you can enable GPU hardware acceleration in the browser.

The above is the full content of this article. I hope it will be helpful for everyone’s study. I also hope that everyone will support 123WORDPRESS.COM.

<<:  Operations of communication between Docker containers and external network communication

>>:  iframe adaptive size implementation code

Recommend

Complete steps to use samba to share folders in CentOS 7

Preface Samba is a free software that implements ...

Using Zabbix to monitor the operation process of Oracle table space

0. Overview Zabbix is ​​an extremely powerful ope...

Compile CPP files using G++ in Ubuntu

When I used g++ to compile the cpp file for the f...

Vue uniapp realizes the segmenter effect

This article shares the specific code of vue unia...

Steps to install RocketMQ instance on Linux

1. Install JDK 1.1 Check whether the current virt...

js to achieve star flash effects

This article example shares the specific code of ...

Design reference WordPress website building success case

Each of these 16 sites is worth reading carefully,...

Solution to MySQL Installer is running in Community mode

Today I found this prompt when I was running and ...

Analyze MySQL replication and tuning principles and methods

1. Introduction MySQL comes with a replication so...

Installation tutorial of MySQL 5.1 and 5.7 under Linux

The operating system for the following content is...

How to create a child process in nodejs

Table of contents Introduction Child Process Crea...

Tutorial on using Multitail command on Linux

MultiTail is a software used to monitor multiple ...

Specific use of MySQL window functions

Table of contents 1. What is a window function? 1...