preface

Two days ago, I saw an article that made a loading animation of “Sword spirit”, which was very interesting. I stopped by and found that the deformation attribute had not been remembered, so I thought of writing an article to review it.

There are four common deformations

Metamorphosis is a new feature in CSS3. Metamorphosis is the basis of animation, and we will talk about the performance advantages of metamorphosis later. There are four kinds of deformation: movement, rotation, scaling and tilt. These four kinds of deformation basically cover all aspects of our daily use.

mobile

Moving is moving elements from one place to another, similar to relative positioning. Let’s look at the basic API:

attribute Deformation function describe
transform translateX(20px) I’m going to go some distance in x
transform translateY(20px) I’m going to go some distance in y
transform translateZ(20px) I’m going to go some distance to Z
transform translate(20px, 20px) I’m going to go some distance toward x and y
transform translate3d(20px, 20px, 20px) I’m going to go some distance toward x,y, and z

In general, the deformation function is easy to remember, very neat, we just need to know where the xyz axis points, x points to the right, Y points down, and Z points to the outside of the screen (toward your eyes)

rotating

The rotation and movement apis are pretty much the same, so let’s list them:

attribute Deformation function describe
transform rotateX(45deg) How many degrees about the x axis
transform rotateY(45deg) How many degrees about the y axis
transform rotateZ(45deg) How many degrees about the z axis
transform rotate(45deg) How many degrees about the z axis
transform rotate3d(45deg, 45deg, 45deg) How many degrees about the x,y,z axis

One thing to note here is that the orientation of the xyz axis changes as the element is deformed, always close to the surface of the element. For example, in our rotation here, if the element is rotated 90 degrees about the Y axis, the X axis points into the screen, the Y axis still points down, and the Z axis points to the right. Let’s look at an example:


  <head>
    <title>Document</title>
    <style>
      div {
        width: 200px;
        height: 200px;
      }
      .stage {
        border: dashed 2px green;
        perspective: 1500px;
      }
      .performer {
        background-color: #ccc;
        transform: rotateY(85deg) translateZ(50px);
      }
    </style>
  </head>
  <body>
    <div class="stage">
      <div class="performer"></div>
    </div>
  </body>
Copy the code

In this example, we rotated the element 85deg around the Y axis and then moved it 50px along the Z axis, which is already pointing to the right, since the Z axis is always perpendicular to the surface of the element.

Another attribute we need to pay attention to is the perspective attribute, which is called depth of field, indicating the distance between the eyes and the stage, which is also the parent box. Note that this attribute must be set on the stage to take effect. Generally speaking, the closer we are to the stage, the better the 3D effect will be; the further away from the stage, the weaker the effect will be.

Of course, the element itself can also set the depth of field via transform: Perspective (1500px) rotateY(85deg). Note that the Perspective () function must come first as the first property value of the transform.

Another interesting property is transform-Origin. This property is called deformation origin. The default origin is at the center of the element. The basic usage is transform-origin: X, y, z, x, y, you can take the left, center, right, top, bottom, px, % type, such as the value of the said the plane coordinate origin from the top left corner of the element migration, z can only write the px said positioning in the z axis. Let’s use rotation to see what it looks like:

 <head>
    <style>
      div {
        width: 200px;
        height: 200px;
      }
      .stage {
        margin: 0px auto;
        border: dashed 2px green;
        perspective: 1500px;
      }
      .performer {
        background-color: #ccc;
        transform: rotateY(85deg);
        transform-origin: left top;
      }
    </style>
  </head>
  <body>
    <div class="stage">
      <div class="performer"></div>
    </div>
  </body>
Copy the code

We set the origin of the coordinate axis at the top left corner, and the Y-axis is the left edge of the element, and we see that rotation around the Y-axis is like opening a door.

The transform-origin property affects rotation, scaling, and tilting.

The zoom

Zooming is relatively simple, commonly used is to zoom in and out elements in 2d plane, the basic API is as follows:

attribute Deformation function describe
transform ScaleX (0.1) Scale along the X-axis
transform ScaleY (0.1) Scale along the Y-axis
transform Scale (0.1, 0.2) Scale along the X and Y axes

The parameter in the scale function is a unitless value. The default value is 1, smaller than 1, and larger than 1, enlarged. Let’s look at an example:

  <head>
    <style>
      div {
        width: 200px;
        height: 200px;
      }
      .stage {
        margin: 200px auto;
        border: dashed 2px green;
      }
      .performer {
        background-color: #ccc;
        transform: scale(0.5.2);
      }
    </style>
  </head>
  <body>
    <div class="stage">
      <div class="performer"></div>
    </div>
  </body>
Copy the code

tilt

Slant is also commonly used in 2d planes, where an element has a slant Angle relative to the X and Y axes.

attribute Deformation function describe
transform skewX(45deg) It’s tilted relative to the X axis
transform skewY(45deg) It’s tilted relative to the Y axis
transform skew(45deg, 45deg) Tilted relative to the X and Y axes

Let’s look at an example:

  <head>
    <style>
      div {
        width: 200px;
        height: 200px;
      }
      .stage {
        margin: 200px auto;
        border: dashed 2px green;
      }
      .performer {
        background-color: #ccc;
        transform: skewX(45deg);
      }
    </style>
  </head>
  <body>
    <div class="stage">
      <div class="performer"></div>
    </div>
  </body>
Copy the code

In this example, we tilt the element 45deg counterclockwise along the X axis. You can see exactly how the element is tilted in real development, not memorizing it.

Do a sword breath loading animation

I learned this animation from another article and thought it was cool, so I decided to implement it myself and talk about it according to my own ideas.

Creating an animation can be done in three steps:

  1. Making static styles
  2. Add the deformation
  3. Add frame animation

A “Sword spirit” loaded 🌪️ # Nuggets article # juejin.cn/post/700177…

Making static styles

Let’s make a static style first. The sword style is essentially a round border, so we can do it with borders and rounded corners. The code is as follows:

  <head>
    <style>
      /* Initialize */
      * {
        padding: 0;
        margin: 0;
      }
      /* Black background, add depth of field */
      .container {
        width: 100vw;
        height: 100vh;
        background-color: # 000;
        perspective: 1500px;
      }
      /* Create a box with a center and border */
      .sword {
        position: absolute;
        left: 50%;
        top: 50%;
        margin-left: -100px;
        margin-top: -100px;
        width: 200px;
        height: 200px;
        border-bottom: solid 3px #fff;
        border-radius: 50%;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="sword sword-1"></div>
      <div class="sword sword-2"></div>
      <div class="sword sword-3"></div>
    </div>
  </body>
Copy the code

Add the deformation

In the previous step, the three blades overlapped and we added the rotation deformation to separate them. The code is as follows:

  </head>
    <style>
      /* Add rotation deformations */
      .sword-1 {
        transform: rotateX(127deg) rotateY(21deg) rotateZ(299deg);
      }

      .sword-2 {
        transform: rotateX(55deg) rotateY(50deg) rotateZ(90deg);
      }

      .sword-3 {
        transform: rotateX(135deg) rotateY(329deg) rotateZ(203deg);
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="sword sword-1"></div>
      <div class="sword sword-2"></div>
      <div class="sword sword-3"></div>
    </div>
  </body>
Copy the code

I give my own Suggestions about how to debug animation, we can take a frame in the animation for debugging, such as random screenshot of a frame animation, I constantly adjust the rotation Angle and then through the browser debugging tools to make their own effects and screenshots, because each firm but gentle movement model is consistent with the rotate at a constant speed (), so as long as one of the frame is a consistent, later will be consistent.

This is a screenshot I took from the animation

This is me using the debug tool to adjust the rotation Angle

Add frame animation

Once the deformation is done, the next step is to animate the element. The essence of animation is to switch between multiple states, each state is a frame, and usually we just need to identify the key frame and the browser will automatically complete the intermediate frame for us. In this case, the motion mode of each blade breath is uniform rotation, so the starting frame is the deformation state defined in the previous step, and the ending frame is 360deg rotation around the Z-axis. Let’s look at the code:

/* Add frame animation */<head>
     <style>
      .sword-1 {
        animation: sword-1 1s linear infinite;
      }

      .sword-2 {
        animation: sword-2 1s linear infinite;
      }

      .sword-3 {
        animation: sword-3 1s linear infinite;
      }

      @keyframes sword-1 {
        /* Use the rotation deformation of the previous step as the starting frame */
        from {
          transform: rotateX(127deg) rotateY(21deg) rotateZ(299deg);
        }
        /* The movement mode of Jianqi is to rotate once, so 360deg will be the last frame */
        to {
          transform: rotateX(127deg) rotateY(21deg) rotateZ(-61deg); }}@keyframes sword-2 {
        /* Use the rotation deformation of the previous step as the starting frame */
        from {
          transform: rotateX(55deg) rotateY(50deg) rotateZ(90deg);
        }
        /* The movement mode of Jianqi is to rotate once, so 360deg will be the last frame */
        to {
          transform: rotateX(55deg) rotateY(50deg) rotateZ(450deg); }}@keyframes sword-3 {
        /* Use the rotation deformation of the previous step as the starting frame */
        from {
          transform: rotateX(135deg) rotateY(329deg) rotateZ(203deg);
        }
        /* The movement mode of Jianqi is to rotate once, so 360deg will be the last frame */
        to {
          transform: rotateX(135deg) rotateY(329deg) rotateZ(-157deg); }}</style>
  </head>
  <body>
    <div class="container">
      <div class="sword sword-1"></div>
      <div class="sword sword-2"></div>
      <div class="sword sword-3"></div>
    </div>
  </body>

Copy the code

When the browser automatically completes the intermediate frame for us, the element moves. One thing to note here is that for the end frame we say 360deg around the Z-axis, but whether we increase 360deg or decrease 360deg depends on whether we want the element to rotate clockwise or counterclockwise.

Why is deformation performance better?

Finally, let’s talk about the performance benefits of transfiguration. Translate (). You might wonder why I add such a moving transfiguration. Sure, position works, but if you want to keep changing positions, especially in animations, position doesn’t perform as well as translate(), and we’ll explain why.

Once the DOM and CSS have been identified, the browser begins the rendering process, which is usually divided into three steps: layout, drawing, and composition.

In a layout, the browser determines how much space each element occupies, and rearrangements are triggered when the size or position of the element changes.

By default, all elements are in the main layer, but sometimes certain elements will be extracted into separate layers. The main layer will be rendered by CPU, and the separate layer will be rendered by GPU, so called hardware acceleration. This is where the transform performance comes in. When the browser detects that an element uses the Transform property and its value is still changing, it extracts the element into a separate layer and renders it, without affecting the main layer when it is redrawn.

The final step is compositing, where the browser combines layers into a single page and performs the compositing in a specific order so that some layers are on top of others.

Let’s compare position and transform to see if they have separate layers. Position:

  <head>
    <style>
      div {
        width: 200px;
        height: 200px;
        border: solid 1px #ccc;
        position: absolute;
        animation: hd 2s linear infinite;
      }

      @keyframes hd {
        from {
          left: 100px;
        }
        to {
          left: 300px; }}</style>
  </head>
  <body>
    <div class="d1"></div>
  </body>
Copy the code

Then the transform:

  <head>
    <style>
      div {
        width: 200px;
        height: 200px;
        border: solid 1px #ccc;
        position: absolute;
        animation: hd 2s linear infinite;
      }

      @keyframes hd {
        from {
          transform: translateX(100px);
        }
        to {
          transform: translateX(300px); }}</style>
  </head>
  <body>
    <div class="d1"></div>
  </body>
Copy the code

Obviously, we found that the transform property changes the browser to separate div elements into separate layers, which takes up more memory, but makes it more efficient. You’ve probably heard that CSS animations perform better than JS animations. JS animations also change the width, height, or position of elements. This triggers rearrangements and redraws that CSS animations do not have with transform morphing.

In summary, changes to the transform property do not cause: 1. Page reorder 2. Redraw the main layer, so better performance.

The end of the

Another 3000 word article, the world of technology is really rich and interesting, there is a long way to go, I hope one day we can do whatever we want in the world of technology.