How to Create Web Animations with Anime.js

How to Create Web Animations with Anime.js
There are many JavaScript animation libraries out there, but Anime.js is one of the best. It’s easy to use, has a small and simple API, and offers everything you could want from a modern animation engine. The library has a small file size and supports all modern browsers, including IE/Edge 11+.

The only thing that could stop you from using Anime.js right away is its minimal, zen-like documentation. I like the compact, structured, elegant approach it takes, but I think that a more detailed explanation would be helpful. I’ll try to fix this issue in this tutorial.

Getting Started With Anime.js

To get started, download and include the anime.js file in your HTML page:

<script src="path/to/anime.min.js"></script>

Alternatively, you can use the latest version of the library hosted on a CDN:

<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/anime.min.js"></script>

Now, to create an animation, we use the anime() function, which takes an object as an argument. In that object, we describe all the animation details.

let myAnimation = anime({
  /* describe the animation details */
});

There are several kinds of properties used to describe the animation. They are grouped into four distinct categories:

  • Targets – this includes a reference to the element(s) we want to animate. It could be a CSS selector (div, #square, .rectangle), DOM node or node list, or plain JavaScript object. There is also an option to use a mix of the above in an array.
  • Properties – this includes all properties and attributes that can be animated when dealing with CSS, JavaScript objects, DOM, and SVG.
  • Property Parameters – this includes property-related parameters like duration, delay, easing, etc.
  • Animation Parameters – this includes animation-related parameters like direction, loop, etc.

Let’s now see how this applies in practice. Consider the following example:

let animation = anime({
  targets: 'div',
  // Properties 
  translateX: 100,
  borderRadius: 50,
  // Property Parameters
  duration: 2000,
  easing: 'linear',
  // Animation Parameters
  direction: 'alternate'
});  

Note: I’m not going to cover the HTML and CSS sections of the code in the tutorial. These tend to be easy to grasp without additional explanation. You can find and explore the HTML and CSS in the embedded pens that follow each example.

In the above example:

  1. We select the green square (the styled div).
  2. We move it 100 pixels to the left while transforming it into a circle.
  3. We set all this to happen smoothly in two seconds (linear means that no easing will be applied to the animation).
  4. By setting the direction property to alternate, we instruct the div element to go back to its initial position and shape after animation completion. Anime.js does that by playing the animation in reverse order.

You may notice that I don’t use any units when specifying property values. That’s because if the original value has a unit, it is automatically added to the animated value. So, we can safely omit the units. But if we want to use a specific unit we must add it intentionally.

Let’s create something more meaningful.

Creating a Pendulum Animation

In this example, we will create a pendulum animation. After we “draw” a pendulum using our HTML and CSS skills, it’s time to bring it to life:

let animation = anime({
  targets: '#rod',
  rotate: [60, -60], // from 60 to -60 degrees
  duration: 3000,
  easing: 'easeInOutSine',
  direction: 'alternate',
  loop: true
});    

In this animation, we use the so-called from-to value type, which defines a range of movement for the animation. In our case, the rod of the pendulum is rotated from 60 to -60 degrees. We also use easeInOutSine easing to simulate the natural motion of pendulum which slows down at peaks and gets faster at the bottom. We use the alternate option again to move the pendulum in both directions and set the loop parameter to true to repeat the movement endlessly.

Well done. Let’s move to the next example.

Creating a Battery Charge Animation

In this example, we want to create an animated icon of a charging battery, similar to the icons on our smartphones. This is easily doable with a bit of HTML and CSS. Here is the code for the animation:

let animation = anime({
  targets: '.segment',
  width: 20,
  duration: 300,
  delay: function(el, i, l) {
    return i * 500;
  },
  endDelay: 500,
  easing: 'linear',
  loop: true
});  

Here we have three segments (the green div elements) which expand (by increasing the width property) one after another. To achieve this effect, we need to use different delays for each one. There’s only one delay parameter we can use for an animation, so in this situation, we are going to use a function-based parameter which produces a different value for every target.

To do so, instead of a literal value, we provide a function with three arguments (target, index, and targetsLength). In our case, the function returns the index multiplied by 500 milliseconds, which causes every element to start animating half a second after the previous one.

We also use the endDelay parameter to pause for a moment before the animation starts again.

Improving the Battery Charging Animation

Now, the animation looks good, but let’s improve it a bit by adding a progress label that shows the charge percentage. Here is the code:

let progress = document.querySelector('#progress');

let battery = {
  progress: '0%'
}

let icon = anime({
  targets: '.segment',
  width: 20,
  duration: 300,
  delay: anime.stagger(500),
  endDelay: 500,
  easing: 'linear', 
  loop: true
});    

let label = anime({
  targets: battery,
  progress: '100%',
  duration: 30000,
  easing: 'linear',
  round: 1, 
  update: function() {
    progress.innerHTML = battery.progress
  },
  complete: function() {
    icon.pause();
    icon.seek(icon.duration);
  }  
});  

This example introduces several more library features. We’ll explore them one by one.

First, we create a progress variable, which references the label in the HTML. Then we create the battery object that holds the progress property. Then, we create two animations.

The first animation is almost identical to the previous example, except for the delay parameter. Here we’ll use the Anime.js feature which allows us to animate multiple elements at once. We use the anime.stagger() function for this. In our case, anime.stagger(500) works just like the function-based parameter — it adds a 50-millisecond delay before each element animation.

In the second animation, we use the battery object as the target. Then we set the progress property to be animated to 100%. The round parameter rounds up the animated value to the given decimal. By setting it to 1, we get whole numbers.

Next, we use two of the callbacks which Anime.js offers.

To bind the progress label value from HTML with the battery progress value, we use the update() callback. We also use the complete() callback to stop the animation after the progress equals 100%, and we use the seek() method to set the animation to its completed state.

As a result, the charging animation will play until the progress becomes 100% and then it will stop and force the segments to their end animation state. The icon will appear as fully charged.

Creating More Complex Animations With Keyframes

Up until now, we’ve dealt with one-step animations that move an object from A to B. But what about moving it from A to B to C to D?

In the next example, we’ll explore how to use property keyframes to create multi-step animations. We’ll move a simple square around another one that serves as a box.

let box = document.querySelector('#box');

let animation = anime({
  targets: '#content',   
  translateY: [
    {value: 50, duration: 500},
    {value: 0, duration: 500, delay: 1500},  
    {value: -53, duration: 500, delay: 500},
    {value: 0, duration: 500, delay: 2500},
    {value: 50, duration: 500, delay: 500},
    {value: 0, duration: 500, delay: 1500}  
  ],
  translateX: [
    {value: 53, duration: 500, delay: 1000},
    {value: 0, duration: 500, delay: 2500},
    {value: -53, duration: 500, delay: 500},
    {value: 0, duration: 500, delay: 2500} 
  ],
  easing: 'linear',   
  begin: function() { 
    box.style.borderBottom="none";  
  },
  complete: function() {
    box.style.borderBottom="solid darkorange 3px";     
  }
}); 

First, we create a reference to the box element. We use it in the begin() and complete() callbacks to “open” the box at animation start and “close” it at animation end. Let’s explore how we move the other square — the content.

For each property we want to animate, we use an array of objects where each object describes a particular keyframe.

In our case, we want to move the square vertically and horizontally. So we use translateY and translateX properties and we provide a keyframes array for each of them. The trick to creating a proper movement is to compute the duration and delay parameters correctly — which can be tricky!

The frames are executed from top to bottom and start simultaneously for each property that has a specified keyframes array. Once started, how the ride will continue depends entirely on the way the duration and delay parameters are set. Good luck with the computation!

The result of our animation is that the square exits the box, makes a full orbit around it, and then goes inside again.

Creating Text Effects

We’ve seen an example of staggering above, and now we’ll explore more advanced usage. We’ll use staggering to create a cool text effect.

let animation = anime({
  targets: '.letter',
  opacity: 1,
  translateY: 50, 
  rotate: {
    value: 360,
    duration: 2000,
    easing: 'easeInExpo'
  }, 
  scale: anime.stagger([0.7, 1], {from: 'center'}), 
  delay: anime.stagger(100, {start: 1000}), 
  translateX: [-10, 30]
});     

We’ve put each letter inside a span element. In the animation code, we select all letters, make them visible, and move them 50 pixels down.

Then, we rotate the letters by using a specific property parameter which defines specific parameters to a given property. This gives us more detailed control over the animation. Here, the letters will be rotated 360 degrees in two seconds applying easeInExpo easing.

In the next two properties, we use the stagger() function. We set the scale to be distributed evenly from 0.7 to 1 opacity (using the range value type), beginning from the center (using the starting position option). This makes letters smaller in the middle of the sentence and bigger at both ends.

We set the animation to wait a second before it starts (by defining a start value), and then a 100-millisecond delay is added relatively for each letter.

We intentionally add the translateX property at the end to create the desired effect, which is to rotate the letters in a spiral movement.

Creating Animations with Timelines

A timeline lets you manipulate multiple animations together. Let’s explore a simple example:

let animation = anime.timeline({
  duration: 1000, 
  easing: 'easeInOutSine',
  direction: 'alternate',  
  loop: true
});           

animation.add({
  targets: '.one',
  translateY: -50,
  backgroundColor: 'rgb(255, 0, 0)'
}).add({
  targets: '.two',
  translateY: -50,
  backgroundColor: 'rgb(0, 255, 0)'
}).add({
  targets: '.three',
  translateY: -50,
  backgroundColor: 'rgb(0, 0, 255)'
});

In this example, we create a ball spinner.

To create a timeline, we use the anime.timeline() function. Then we define common parameters that are inherited for all added animations.

To add an animation to the timeline, we use the add() method, and then we describe the animation in the same manner we’ve already covered.

In our example, we add three animations, one for each ball. The result is that each ball rises and falls one by one.

The problem is that in this basic form, the animation seems very static. Let’s change that.

By default, each animation starts after the previous animation ends. But we can control this behavior by using time offsets. Also, if we want to make the animation more flexible and complex, we have to use animation keyframes. Let’s see how this applies in the following example:

let animation = anime.timeline({
  duration: 1000, 
  easing: 'easeInOutSine',   
  loop: true
});           

animation.add({
  targets: '.one',
  keyframes: [
    {translateY: -50, backgroundColor: 'rgb(255, 0, 0)' },
    {translateY: 0, backgroundColor: 'rgb(128, 128, 128)'}
  ]
}).add({
  targets: '.two',
  keyframes: [
    {translateY: -50, backgroundColor: 'rgb(0, 255, 0)' },
    {translateY: 0, backgroundColor: 'rgb(128, 128, 128)'}
  ]
}, '-=900').add({
  targets: '.three',
  keyframes: [
    {translateY: -50, backgroundColor: 'rgb(0, 0, 255)' },
    {translateY: 0, backgroundColor: 'rgb(128, 128, 128)'}
  ]
}, '-=800');

Here, we remove the direction parameter, because we use keyframes to achieve the back and forth movement. We define animation keyframes by adding a keyframes parameter. As with property keyframes, each object from the array is a keyframe.

To make the balls move smoothly, we use time offsets which are specified as the second parameter to the add() function. In our case, we use values relative to the previous animation.

The result is a smooth ball spinner animation.

Conclusion

I hope that you’ve gained a much better understanding of Anime.js. To continue your learning with this foundational knowledge in hand, I recommend checking out the documentation.

Anime.js is a simple but powerful animation engine that can be used to create a broad range of animations. Let your imagination run wild.

Node.js file streams explained!

Build Your First PWA with Vue and TypeScript

Why Hiring Dedicated Magento Developer is a Good Idea

How to implement server-side pagination in Vue.js with Node.js

Suggest:

Learn Vue.js from scratch 2018

Learn JavaScript - Become a Zero to Hero

JavaScript Programming Tutorial Full Course for Beginners

Vue js Tutorial Zero to Hero || Brief Overview about Vue.js || Learn VueJS 2023 || JS Framework

JavaScript for React Developers | Mosh

An Encounter with JavaScript Objects