banner
cos

cos

愿热情永存,愿热爱不灭,愿生活无憾
github
tg_channel
bilibili

Youth Training Camp | "Frontend Animation Implementation"

Basic Principles of Animation#

What is Animation#

Animation is the process of creating the illusion of motion and change by rapidly displaying a sequence of images that differ only slightly from each other.

——Wikipedia

  • Rapid
  • Sequential arrangement
  • Slight differences from each other
  • The process of creating “illusions”

History of Animation Development#

Today, front-end animation technology has become widespread.

  1. Common front-end animation technologies

    • Sprite animation, CSS animation, JS animation, SVG animation, and WebGL animation
  2. Classification by application

    • UI animation, web-based game animation, and animated data visualization

The emergence of GIF and Flash once became mainstream, and around the year 2000, Apple Inc. believed that Flash would lead to increased CPU load and faster battery drain, announcing a complete abandonment of Flash, which significantly improved the battery life of all Apple devices. Nowadays, web animations are mainly based on CSS and JS animations.

Computer Animation#

Computer Graphics

The foundation of computer vision, covering mathematical construction methods for points, lines, surfaces, bodies, and fields.

  • Input, storage, and compression of geometric and graphic data.
  • Algorithms describing textures, curves, lighting, and shadows.
  • Data output of object graphics (graphics interfaces, animation techniques), hardware, and graphics interaction technologies.
  • Relevant technical standards for graphic development software.

Computer Animation is a branch of computer graphics, mainly including 2D and 3D animation. Regardless of how simple the animation is, it always requires defining two basic states: starting state and ending state. Without them, we cannot define the interpolated state, thus filling the gap between the two.

1.gif

Rapid √ Sequential arrangement × Slight differences × Creating “illusions” ×

As can be seen, the animation above is only rapid and does not create an illusion, which brings us to the concept of frame rate~~(This concept should be familiar to gamers)~~

  • Frame: A series of continuously changing images, each image is one frame.

  • Frame rate: Used to measure the number of frames within a certain time period, with the usual measurement unit being FPS (frames per second).

  • Frame rate and the human eye: Generally, 10-12 frames per second are perceived as coherent; this phenomenon is called persistence of vision. For some computer animations and games, below 30 FPS will feel noticeably choppy, while the mainstream screen and graphics card output is 60 FPS, resulting in a significantly smoother effect.

Next, we will fill the gap between the starting point and the ending point, attempting to make the animation coherent.

image.png

There are two ways to fill the gap:

  • Interpolated animation
    • In traditional animation, the main artist draws keyframes and hands them over to the cleanup department, where the interpolated animators fill in the keyframes for delivery.
    • (In this analogy, the interpolated animators for front-end animation are handled by the browser, such as @keyframes and transition)
  • Frame-by-frame animation
    • This means that every frame of the entire piece is hand-drawn. (For example, CSS's steps implementation of sprite animation)

Classification of Front-end Animation#

CSS Animation#

CSS (Cascading Style Sheets) is a style sheet language used to describe the presentation of HTML or XML (including XML-based languages like SVG, MathML, XHTML). The animation property in CSS is a shorthand for properties like animation-name, animation-duration, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, animation-fill-mode, and animation-play-state.

animation-name#

The animation-name property specifies a series of animations to apply, with each name representing an animation sequence defined by @keyframes. Its values are as follows:

  • none (initial value) is a special keyword indicating no keyframes. It can disable the animation without changing the order of other identifiers or make cascading animation styles ineffective.
  • IDENT is a string that identifies the animation, composed of case-sensitive letters a-z, numbers 0-9, underscores (_), and/or hyphens (-). The first non-hyphen character must be a letter, numbers cannot precede letters, and two hyphens cannot appear at the start.

Multiple animation definitions are separated by commas.

/* Single animation */
animation-name: none;
animation-name: test_05;
animation-name: -specific;
animation-name: sliding-vertically;

/* Multiple animations */
animation-name: test1, animation4;
animation-name: none, -moz-specific, sliding;

/* Global values */
animation-name: initial
animation-name: inherit
animation-name: unset

animation-duration#

The animation-duration property specifies the duration of an animation cycle. The default value is 0s, indicating no animation.

Its value is the duration of an animation cycle, measured in seconds (s) or milliseconds (ms); unitless values are invalid. Multiple values can be specified, corresponding one-to-one with animation-name.

Note: Negative values are invalid; the browser will ignore this declaration, but some early prefixed declarations will treat negative values as 0s.

/* Single animation */
animation-duration: 6s
animation-duration: 120ms

/* Multiple animations */
animation-duration: 1s, 15s
animation-duration: 10s, 30s, 230ms

animation-timing-function#

The animation-timing-function property defines the rhythm of CSS animations during each animation cycle. It can have one or more values, corresponding one-to-one with animation-name. CSS defines several easing functions that can be called to achieve easing effects.

For keyframe animations, the timing function applies to a keyframe cycle rather than the entire animation cycle, meaning from the start of the keyframe to the end of the keyframe.

The easing function defined in a keyframe block applies to that keyframe; if the keyframe does not define an easing function, the easing function defined for the entire animation is used.

/* 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;
animation-timing-function: step-start;
animation-timing-function: step-end;

/* Function values */
animation-timing-function: cubic-bezier(0.1, 0.7, 1.0, 0.1);
animation-timing-function: steps(4, end);
animation-timing-function: frames(10);

/* Multiple animations */
animation-timing-function: ease, step-start, cubic-bezier(0.1, 0.7, 1.0, 0.1);

/* Global values */
animation-timing-function: inherit;
animation-timing-function: initial;
animation-timing-function: unset;

animation-delay#

The animation-delay property defines when the animation starts, that is, the length of time from when the animation is applied to the element until the animation begins (how long to delay before starting).

0s is the default value for this property, indicating that the animation starts immediately after being applied to the element. Otherwise, the value of this property represents the length of time from when the animation style is applied to the element until it starts executing.

Defining a negative value will cause the animation to start immediately. However, the animation will start from a certain position in its animation sequence. For example, if the value is set to -1s, the animation will start immediately from the 1-second position in its animation sequence.

If a negative value is specified for the animation delay but the starting value is hidden, the starting value will be taken from the moment the animation is applied to the element.

animation-delay: 3s;
animation-delay: 2s, 4ms;

animation-iteration-count#

The animation-iteration-count property defines the number of times the animation runs before ending. It can be 1 time or infinite loops.

  • infinite

    Plays the animation in an infinite loop.

  • <number>

    The number of times the animation plays; the default value is 1. It can use decimal values to define loops to play part of the animation cycle: for example, 0.5 will play to half of the animation cycle. It cannot be negative.

/* Value as keyword */
animation-iteration-count: infinite;

/* Value as number */
animation-iteration-count: 3;
animation-iteration-count: 2.4;

/* Specify multiple values */
animation-iteration-count: 2, 0, infinite;

Its multiple values differ from duration; it switches its execution count at the start and end of each animation.

animation-direction#

The animation-direction property indicates whether the animation plays in reverse.

  • normal (default value)

    The animation plays forward within each loop, meaning that at the end of each animation loop, the animation resets to the starting point and starts again, which is the default property.

  • alternate

    The animation runs in reverse alternately, meaning that during reverse runs, the animation steps backward, and the timing function also runs in reverse; for example, ease-in becomes ease-out in reverse. The count depends on whether the starting iteration is odd or even.

  • reverse

    The animation runs in reverse, meaning that at the end of each cycle, the animation runs from end to start.

  • alternate-reverse

    Reverse alternation, meaning it starts in reverse alternately.

    The animation runs in reverse the first time, then forward the next time, and continues to alternate. The count of odd or even iterations starts from 1.

animation-direction: normal
animation-direction: reverse
animation-direction: alternate
animation-direction: alternate-reverse
animation-direction: normal, reverse
animation-direction: alternate, reverse, normal

animation-fill-mode#

The animation-fill-mode property sets how CSS animations apply styles to their target before and after execution.

/* Single animation */
animation-fill-mode: none;
animation-fill-mode: forwards;
animation-fill-mode: backwards;
animation-fill-mode: both;

/* Multiple animations */
animation-fill-mode: none, backwards;
animation-fill-mode: both, forwards, none;
  • none (default)

    When the animation is not executed, the animation will not apply any styles to the target, but will display the CSS rules already assigned to that element. This is the default value.

  • forwards

    The target will retain the last computed value encountered during execution. The last keyframe depends on the values of animation-direction and animation-iteration-count (meaning the last keyframe will remain the same afterward).

  • backwards

    The animation will immediately apply the value defined in the first keyframe when applied to the target, and retain this value during the animation-delay period. (This is important; the delay is in seconds). The first keyframe depends on the value of animation-direction: animation-direction first relevant keyframe normal or alternate 0% or from reverse or alternate-reverse 100% or to.

  • both

    The animation will follow the rules of forwards and backwards, thus extending the animation properties in both directions. (This means both of the above).

Note: When you specify multiple comma-separated values on animation-* properties, they will be assigned to the animations specified in the animation-name property according to the number of values. For more information, see Setting Multiple Animation Property Values.

animation-play-state#

The animation-play-state property defines whether an animation is running or paused. It can be queried to determine whether the animation is currently running. Additionally, its value can be set to resume a paused animation. Resuming a paused animation will start from where it was paused, rather than from the start of the animation sequence.

  • running

    The current animation is running.

  • paused

    The current animation has been stopped.

/* Single animation */
animation-play-state: running;
animation-play-state: paused;

/* Multiple animations */
animation-play-state: paused, running, running;

/* Global values */
animation-play-state: inherit;
animation-play-state: initial;
animation-play-state: unset;

An example: CSS BEER! (codepen.io)

I checked out this expert's other projects, and they are all very interesting! #codevember - 19 - CSS Eggs (codepen.io), Periodic Table of Elements - HTML/CSS (codepen.io)

transform API#

The transform property allows you to rotate, scale, skew, or translate a given element. This is achieved by modifying the coordinate space of the CSS visual formatting model.

The transform-origin specifies the position of the origin; the default transformation origin is center.

The transform property can be specified as the keyword value none or one or more <transform-function> values.

  • transform-function

    One or more CSS transformation functions to apply. Transformation functions are multiplied in order from left to right, meaning that composite transformations are effectively applied from right to left.

    • scale (scaling) note that its center is transform-origin.

      image.png

      // Scale down to 50% along the x-axis
      transform: scale(0.5);
      // Scale down to 50% along the x-axis, scale up to 2 times along the y-axis
      transform: scale(0.5, 2);
      
    • rotate (rotation) rotates the element around the origin without distortion (as specified by the transform-origin property). The amount of movement is defined by the specified angle; if it is positive, the movement will be clockwise, and if it is negative, it will be counterclockwise. A rotation of 180° is called point reflection.

      image.png

      transform: rotate(30deg);
      
    • skew (skewing) parameters represent the skew angle, in degrees.

      One parameter indicates the skew angle in the horizontal direction (ax);

      Two parameters indicate horizontal and vertical (ax, ay).

      transform: skew(ax)       
      transform: skew(ax, ay)
      
  • none

    No transformations are applied.

Note: It can only transform elements positioned by the box model; generally, if an element has display: block, it is positioned by the box model.

The transition property triggers transition animations when the DOM is loaded or when a class changes. This property is a shorthand for transition-property, transition-duration, transition-timing-function, and transition-delay.

/* Apply to 1 property */
/* property name | duration */
transition: margin-right 4s;

/* property name | duration | delay */
transition: margin-right 4s 1s;

/* property name | duration | timing function */
transition: margin-right 4s ease-in-out;

/* property name | duration | timing function | delay */
transition: margin-right 4s ease-in-out 1s;

/* Apply to 2 properties */
transition: margin-right 4s, color 1s;

/* Apply to all changed properties */
transition: all 0.5s ease-out;

/* Global values */
transition: inherit;
transition: initial;
transition: unset;

Keyframe Animation#

The @keyframes at-rule controls the intermediate steps in a CSS animation sequence by defining the styles of keyframes (or waypoints). Compared to transitions, keyframes can control the intermediate steps of the animation sequence.

// Slide in from the left
@keyframes slidein {
  from {
    transform: translateX(0%); 
  }
  to {
    transform: translateX(100%);
  }
}
// 
@keyframes identifier {
  0% { top: 0; }
  50% { top: 30px; left: 20px; }
  50% { top: 10px; }
  100% { top: 0; }
}

For example: my CSS Animation practice (codepen.io)

@keyframes identifier {
  0% { top: 0; left: 0; }
  50% { top: 60%; left: 60%;}
  100% {  top: 0; left: 0; }
}
@keyframes slidein {
  from {
    transform: translateX(0%); 
  }
  to {
    transform: translateX(100%);
  }
}
body  >div {
  position: absolute;
  display:flex;
  align-items:center;
  justify-content: center;
  color: #fafafa;
  background-color: #141414;
  padding: 10px;
  width:20%; height:20%;
/*   Slide from top left to bottom right, lasting 5s, delayed 1s, infinite loop */
/*   animation: identifier 5s linear 1s infinite; */
/*   Slide right, lasting 1s, twice */
  animation: slidein 1s 2;
}

In summary:

The advantages of CSS animations: simple, efficient, and declarative. They do not rely on the main thread and use hardware acceleration (GPU), allowing for simple control of keyframe animation playback and pause.

Disadvantages: Cannot dynamically modify or define animations, animations with different content cannot achieve synchronization, and multiple animations cannot stack on each other.
Applicable scenarios: Simple H5 activities/promotion pages.
Recommended libraries: Animate.css, CSShake, etc.

SVG Animation#

SVG is an XML-based vector graphics description language that can work well with CSS and JS. There are generally three ways to implement SVG animations: SMIL, JS, CSS.

  • SMIL: Synchronized Multimedia Integration Language
  • Using JS to manipulate SVG animations is self-evident; there are many existing libraries. For example, the classic Snap.svg and anime.js can help us quickly create SVG animations. Additionally, HTML itself has native Web Animation implementations. Here are two examples from the teacher:

The implementation principle of the first animation:

Text Dissolve Principle - filter#

The filter property applies graphical effects such as blurring or color shifting to elements. Filters are commonly used to adjust the rendering of images, backgrounds, and borders. Basic case: https://codepen.io/jiangxiang/pen/XWeQGQK

  • Blur gradually decreases, and when the blur is almost gone, setting its opacity to 0 hides it, achieving a dissolve effect.

JS Stroke Principle - stroke#

Using stroke-dashoffset and stroke-dasharray together to achieve a stroke effect.
The stroke-dasharray property controls the pattern of dashes and gaps used to stroke the outline. It is a sequence of numbers separated by commas or spaces, specifying the lengths of dashes and gaps. If an odd number of values is provided, the sequence of values will repeat once, resulting in an even number of values. Therefore, 5,3,2 is equivalent to 5,3,2,5,3,2.
The stroke-dashoffset property specifies the distance from the start of the path to the dash pattern.

Here’s an example from the teacher: stroke-dasharray & stroke-dashoffset (codepen.io)

// 5px solid line 5px gap x1y1 -> x2y2
<line stroke-dasharray="5, 5" x1="10" y1="10" x2="190" y2="10" />
// 5px solid line 10px gap
<line stroke-dasharray="5, 10" x1="10" y1="30" x2="190" y2="30" />
// 10px solid line 5px gap
<line stroke-dasharray="10, 5" x1="10" y1="50" x2="190" y2="50" />
// 5px solid line 1px gap...
<line stroke-dasharray="5, 1" x1="10" y1="70" x2="190" y2="70" />
<line stroke-dasharray="1, 5" x1="10" y1="90" x2="190" y2="90" />
<line stroke-dasharray="0.9" x1="10" y1="110" x2="190" y2="110" />
<line stroke-dasharray="15, 10, 5" x1="10" y1="130" x2="190" y2="130" />
<line stroke-dasharray="15, 10, 5, 10" x1="10" y1="150" x2="190" y2="150" />
<line stroke-dasharray="15, 10, 5, 10, 15" x1="10" y1="170" x2="190" y2="170" />
// Total length 180 180 solid 180 gap (all solid) at this point changing the dashoffset value can achieve the stroke effect
<line stroke-dasharray="180" stroke-dashoffset="0" x1="10" y1="190" x2="190" y2="190" />

image.png

For simple lines, you can directly know their total length and thus achieve the stroke effect by initializing the dashoffset. But what about irregular shapes?

By using path.getTotalLength();

Path - The d attribute defines
Uppercase letters are followed by absolute coordinates x,y, while lowercase letters are relative coordinates dx,dy. M/m draws the starting point.

  • L/l draws a line segment.
    C/c draws a Bezier curve.
    Z/z connects the current point to the starting point with a straight line.

  • Calculate the length of the path - path.getTotalLength();

  • Calculate the coordinates of a point on the path - path.getPointAtLength(lengthNumber);

Here’s the teacher’s example: SVG Using stroke-dashoffset and stroke-dashoffset to achieve stroke effect (codepen.io)

  • The advantages of SVG animations: Achieving animations through vector elements, ensuring good clarity on different screens. It can achieve some special effects: writing, morphing, ink diffusion, etc.

  • Disadvantages: The usage is relatively complex, and excessive use may lead to performance issues.

JS Animation#

JS can achieve complex animations, manipulating CSS, SVG, and also drawing using the canvas animation API.

How to Choose?#

CSS Implementation

  • Advantages

    • Browsers optimize CSS3 animations, giving CSS3 animations a slight performance advantage (creating a new layer to run the animation).
    • The code for CSS3 animations is relatively simple.
  • Disadvantages

    • Animation control is not flexible enough.
    • Compatibility is poor.
    • Some animations cannot be achieved (parallax effects, scroll animations).
  • CSS can be used for simple animations.

JS Implementation

  • Advantages

    • Flexible usage; when defining a keyframe sequence for an animation, various parameters (JS animation functions) can be adjusted based on different conditions to change the animation method. (CSS would have a lot of code redundancy).

    • Compared to CSS, the granularity of JS keyframes is coarser, and the time functions in CSS are limited, which JS can compensate for.

    • CSS finds it difficult to achieve more than two state transitions (either using keyframes or requiring multiple animations to trigger with delays, and considering looping or pausing the animation in reverse, which is extremely complex).

  • Disadvantages

    • When using JS, tuning is not as straightforward as CSS; CSS tuning methods are fixed.
    • For browsers with poor performance and compatibility, CSS can achieve graceful degradation, while JS requires additional code for compatibility, which can affect the size of the packaged product.

In summary:

  • Use CSS for small independent states of UI elements.
  • Use JavaScript when extensive control over animations is needed.
  • In specific scenarios, SVG can be used, with CSS or JS manipulating SVG changes (like the aforementioned dissolve and stroke effects).

Implementing Front-end Animation#

JS Animation Function Encapsulation#

function animate({easing, draw, duration}) {
  let start = performance.now(); // Get the current time
  return new Promise(resolve => {
    requestAnimationFrame(function animate(time) {
      let timeFraction = (time - start) / duration;
      if(timeFraction > 1) timeFraction = 1;
      
      let progress = easing(timeFraction);

      draw(progress);
      
      if(timeFraction < 1) {
          requestAnimationFrame(animate);
      } else {
          resolve();
      }
    });
  });
}

In this function, we first get the current system time using performance.now(), which increases at a constant rate and is not affected by system time, represented as a floating-point number with microsecond precision, making it difficult to tamper with. Parameter descriptions:

  • draw function

    • You can think of it as a paintbrush; as the function executes, this paintbrush function will be repeatedly called and passed the current execution progress, with progress depending on the value of easing. For example:

      const ball = document.querySelector('.ball');
      const draw = (progress) => {
          ball.style.transform = `translate(${progress}px, 0)`;
      }
      
  • easing function

    • The easing function alters (or distorts) the timing of the animation, making it linear/non-linear or multidimensional. For example:

      easing(timeFraction) {
          return timeFraction ** 2;   // Square of timeFraction
      }
      
  • duration is the duration in milliseconds.

  • The reason for returning a Promise:

    • Promise is an object that represents the eventual completion or failure of an asynchronous operation.

    • Animations can be continuous, and Promise supports sequential calls through the then function or await, making it easy to obtain the final state of the animation.

  • This animation function implements a finite time animation encapsulation.

  • RequestAnimationFrame (rAF) vs SetTimeout vs SetInterval

    • Use requestAnimationFrame! Why?

      This built-in method allows you to set a callback function to run when the browser is ready to repaint. Typically, this is quick, but the exact timing depends on the browser.
      setTimeout and setInterval do not run the callback when the page is in the background, as there is no repaint; thus, the animation will be paused and will not consume resources. Reference: javascript - requestAnimationFrame loop not correct FPS - Stack Overflow

      Reflow: If part of the render tree is updated and size changes, a reflow occurs.

      Repaint: If some nodes need updating but do not change the shape of other collections, a repaint occurs. For example, changing an element's visibility, outline, background color, etc., will trigger a repaint.

Simple Animation#

The core idea of executing animations in JS:

∆r = ∆v∆t

Simply put: r is distance, v is speed, and t is time. By scaling with a coefficient, we ensure the realism of the animation.

For example, uniform motion; the teacher's example is very comprehensive JS Encapsulated Animation Function (codepen.io) (make sure to check it out!).

const ball = document.querySelector('.ball');
const draw = (progress) => {
    ball.style.transform = `translate(${progress}px, 0)`;
}
// Uniform motion along the x-axis
animate({
    duration: 1000,
    easing(timeFraction) {
        return timeFraction * 100;
    },
    draw
})

1.gif

  • Gravity: h = g * t ^2^
t^2^ // Gravity
const gravity = () => {
  const draw = (progress) => {	// Height 500
    ball.style.transform = `translate(0, ${500 * (progress - 1)}px)`;
  };
  animate({
    duration: 1000,
    easing(timeFraction) {
      return timeFraction ** 2;	// t squared
    },
    draw,
  });
};

2.gif

  • Friction: time becomes 2t - t^2^
// Friction
const friction = () => {
  // Initial height 500px
  const draw = (progress) => {
    ball.style.transform = `translate(0, ${500 * (progress - 1)}px)`;
  };
  animate({
    duration: 1000,
    easing(timeFraction) {
      // Initial speed coefficient is 2
      return timeFraction * (2 - timeFraction);
    },
    draw,
  });
};

3.gif

  • Horizontal throw (uniform speed on the x-axis, accelerated on the y-axis), meaning that the y-axis is similar to gravity's t^2^ while the x-axis speed remains constant.
// Horizontal throw x
const horizontalMotion = () => {
  const draw = (progress) => {
    ball.style.transform = `translate(${500 * progress.x}px, ${500 * (progress.y - 1)}px)`;
  };

  // Two directions, uniform motion along the x-axis, accelerated motion along the y-axis
  animate({
    duration: 1000,
    easing(timeFraction) {
      return {
        x: timeFraction,
        y: timeFraction ** 2,
      }
    },
    draw,
  });
};

4.gif

There are many more; if you want to add more, just add new properties to the object returned by easing, such as rotation:

  • Rotation + Horizontal throw

    // Rotation + Horizontal throw
    const horizontalMotionWithRotate = () => {
      const draw = (progress) => {
        ball.style.transform = `translate(${500 * progress.x}px, ${500 * (progress.y - 1)}px) rotate(${2000 * progress.rotate}deg)`;// Here, 2000 is also a scaling coefficient
      };
    
      // Two directions, uniform motion along the x-axis, accelerated motion along the y-axis
      animate({
        duration: 2000,
        easing(timeFraction) {
          return {
            x: timeFraction,
            y: timeFraction ** 2,
            rotate: timeFraction,
          }
        },
        draw,
      });
    };
    

    5.gif

  • Bow (uniform speed on the x-axis, initial speed on the y-axis is negative and uniformly accelerated)

    // Bow
    const arrowMove = () => {
      // Abstracted, initial value is 2, changes to positive 1 at a critical point and increases uniformly
      const back = (x, timeFraction) => {
        return Math.pow(timeFraction, 2) * ((x + 1) * timeFraction - x);
      }
      const draw = (progress) => {
        ball.style.transform = `translate(${200*progress.x}px, ${ - 500 * progress.y}px)`;
      };
      animate({
        duration: 1000,
        easing(timeFraction) {
          return {
            x: timeFraction,
            y: back(2, timeFraction),
          };
        },
        draw,
      });
    };
    

6.gif

  • Bezier curves cubic-bezier(0,2.11,1,.19) ✿ cubic-bezier.com, Animated Bézier Curves - Jason Davies

    • ps: At this point, it starts to get hardcore, tql

    10.gif

    // Bezier
    const bezier = () => {
      const bezierPath = (x1, y1, x2, y2, timeFraction) => {
        const x = 3 * x1 * timeFraction * (1 - timeFraction) ** 2 + 3 * x2 * timeFraction ** 2 * (1 - timeFraction) + timeFraction ** 3;
        const y = 3 * y1 * timeFraction * (1 - timeFraction) ** 2 + 3 * y2 * timeFraction ** 2 * (1 - timeFraction) + timeFraction ** 3;
        return [x, y];
      }
    
      const draw = (progress) => {
        const [px, py] = bezierPath(0.2, 0.6, 0.8, 0.2, progress);
        // Actual drawing in two dimensions
        ball.style.transform = `translate(${300 * px}px, ${-300 * py}px)`;
      }
    
      animate({
        duration: 2000,
        easing(timeFraction) {
          return timeFraction * (2 - timeFraction);
        },
        draw,
      });
    }
    

    11.gif

Complex Animation#

  • Bouncing ball (using easing function for implementation/automatic decay implementation)

    • Directly check the teacher's example: JS Encapsulated Animation Function (codepen.io). The automatic decay here fills a previous gap: why use Promise? After each execution, it hands the handle back to the above function to check if there is a speed decay, and it will automatically end when the speed reaches 0.

    7.gif

Automatic decay: more complex

8.gif

  • Elliptical motion

    • Just apply the formula, x = a*cos(a), y = b * sin(a)

      // Ellipse
      const ellipsis = () => {
        const draw = (progress) => {
          const x = 150 * Math.cos(Math.PI * 2 * progress);
          const y = 100 * Math.sin(Math.PI * 2 * progress);
          ball.style.transform = `translate(${x}px, ${y}px)`;
        }
        
        animate({
          duration: 2000,
          easing(timeFraction) {
            return timeFraction * (2 - timeFraction);
          },
          draw,
        });
      };
      
      

9.gif

Animation code examples:

  • CodePen can provide a lot of design inspiration.
  • CodeSandbox is convenient for importing SDKs.

Design websites:

Animation production tools (generally used by UE and UI students):

  • 2D: Animate CC, After Effects
  • 3D: Cinema 4D, Blender, Autodesk Maya

SVG:

  • Snap.SVG - A JavaScript library for modern SVG graphics.

  • Svg.js - A lightweight library for manipulating and animating SVG.

JS:

  • GSAP - A JavaScript animation library.

  • TweenJS - A simple yet powerful JavaScript tweening/animation library, part of the CreateJS suite.

  • Velocity - Accelerated JavaScript animations.

CSS:

  • Animate.css - A cross-browser library for CSS animations. Easy to use.

canvas:

  • EaselJS - A library for building high-performance interactive 2D content in HTML5.

  • Fabric.js - A JavaScript canvas library that supports animations.

  • Paper.js - A Swiss army knife for vector graphics scripting.

  • Scriptographer - A JavaScript and browser port of HTML5 Canvas.

  • Pixijs – Create beautiful digital content using the fastest, most flexible 2D WebGL renderer.

In actual work, it is often about converting the animation frames/design files provided by UI into code.

  • When the front-end needs to design and develop independently:

    • Use well-encapsulated animation libraries, making trade-offs from the perspective of development cost and experience.
  • When designers are not very available:

    • Clarity and image formats can be specified, and animations should ideally provide indications or similar case references. Request sprite resources and help compress them (for mobile resource adaptation, etc.).
  • When design resources are abundant:

    • Request designers to export Lottie format files.

      Lottie is a library that can be applied to Android, iOS, Web, and Windows,
      parsing AE animations through Bodymovin and exporting JSON files that can render animations on mobile and web.

      import lottie from 'lottie-web' ;
      this.animation = lottie.loadAnimation({
          container: this.animationRef.current,
          renderer: 'svg',
          loop: false,
          autoplay: false,
          animationData: dataJson,
          path: URL,
      });
      

Optimization#

The general rendering process of a page is JS -> CSS -> Compute Styles --> Layout -> Paint -> Merge Render Layers.

Among them, Layout (reflow) and Paint (repaint) are the most time-consuming parts of the entire process, so we try to avoid these two parts. From a performance perspective, the ideal rendering pipeline is one without layout and painting, only needing to merge render layers.

  • You can check CSS properties and their impact using CSS Triggers.

Recommendations#

  • In practical applications, a simple point to note is that do not use display to trigger the start of animations, as it will cause Layout and Paint. Switching class names is already a good method.

ps: Learned this! I will go change it.

  • CSS3 hardware acceleration, also known as GPU acceleration, is an optimization scheme that uses the GPU for rendering, reducing CPU operations. Since CSS properties like transform do not trigger repaint, it can significantly improve webpage performance. The following CSS properties can trigger hardware acceleration:
    • transform
    • opacity
    • filter
    • Will-change
    • If some elements do not need to use the above properties but require triggering hardware acceleration effects, some tricks can be used to induce the browser to enable hardware acceleration.
      • Algorithm optimization
      • Linear functions instead of real calculations - geometric model optimization
      • Collision detection optimization
      • Memory/cache optimization - off-screen rendering

Summary and Reflections#

Today's lesson was very hardcore, introducing the basic principles of front-end animation, the classification of front-end animations, and how to implement front-end animations, along with related resources and practical methods. It gave me a deeper understanding of front-end animation, and the resources provided at the end were also very helpful~

Most of the content cited in this article comes from Teacher Jiang Xiang's class and MDN (the introduction to CSS animation properties on MDN is very comprehensive and has vivid examples, highly recommended to check out).

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.