HTML & CSS - - By Maria Antonietta Perna

Animating the DOM with Anime.js

Beyond CSS: Dynamic DOM Animation Libraries

Anime.js Animation Library

If you’re looking for a fast and lightweight animation library, Anime.js by Julian Garnier is an option you’d like to consider.

This is the first of a series of articles about tools for dynamic DOM animation, including SVG graphics. I don’t plan to include specialized canvas-WebGL animation libraries or SVG-specific animation libraries. However, if a library is great at animating HTML elements on a webpage (and ideally also SVG graphics), I will consider it for inclusion in this series.

It is not my intention to dissect each library and delve deeply into its code. Instead, I am going to approach each library from the perspective of someone who mainly works with CSS but would like to explore what JavaScript has to offer when it comes to animating the DOM. Therefore, I will be looking for a tool that is great at manipulating the DOM by dynamically adding and removing CSS styles and/or classes for the purposes of animation by means of a syntax that feels familiar to a CSS developer.

Animation on the Web

As Sarah Drasner explains, when talking about web animation, a useful distinction is between user interface/user experience animation and standalone animation.

Research shows how human perception understands the world better on the basis of moving images. This means that we can understand and assimilate information better when it is presented to us in a moving scene rather than in the form of an image or even a series of static images.

UI/UX animation serves the purpose of aiding users as they navigate a website, absorb information on a webpage, or perform a specific task, e.g., signing up for a newsletter, adding an item to the shopping cart, etc.

By contrast, standalone animation is…

Used to illustrate concepts in the body of the page, either alongside or on it’s own.

Sarah Drasner — CSS Conference slides

Here’s an amazing CodePen demo by Sarah to illustrate the point.

The distinction is important because when you’re animating user interfaces, your aim is to help users perform those tasks which go towards meeting the website’s goals. Instead, when creating a standalone animation, you set out to express a certain concept as fully as possible.

That said, both kinds of animation are made for people to enjoy. That’s why, when creating your animations, things like performance and accessibility make all the difference between an animation that delights and one that annoys or even hurts users.

Why Use JavaScript for Animation?

Today CSS offers transitions and animations to add movement to the web. However, when it comes to animation on the web, JavaScript is still a big player. Why is this the case? At last we can run an animation using CSS alone, why on earth would anyone need JavaScript to do the job?

To help you decide between CSS and JavaScript animation, consider the following distinctions by Rachel Nabors.

Animation can be:

  • static: the animation runs from the beginning through to the end without decision-making logic. CSS loaders are a case in point. You can create this kind of animation with CSS alone;
  • stateful: a sidebar that opens and closes at the click of a button is a common example of this type of animation. You can build this using CSS and a tiny bit of JavaScript to add and remove the CSS classes responsible for keeping track of the state of the element in your animation;
  • dynamic: this kind of animation can have different outcomes, which depend on various factors like user interaction, DOM events, the state of the animation of other elements on the same document, etc. You can’t create dynamic animations with just CSS – in this context, JavaScript is most likely your best friend.

Besides dynamic animations, you could turn to JavaScript for a helping hand with your animations if you come across any of the circumstances below:

  • you need to chain or stagger your animations on more than a few elements. In this case, each subsequent animation needs to occur after the previous one has completed. You can do this with CSS alone by coordinating the delay property on each animated element. However, if you need to change even just one value, making the necessary adjustments on all the chained elements can quickly become unmanageable;
  • you are animating SVG graphics. In this case, the drawback is that CSS animation on SVG is not consistently supported across browsers;
  • if your project needs to support older browsers where CSS animation is not available, resorting to a robust JavaScript solution will make your animations more widely available.

If you’d like to read more on this topic, Myth Busting: CSS Animations vs. JavaScript by Jack Doyle, author of the Greensock Animation Platform, makes some good points.

An Up and Coming Alternative: the Web Animations API

The W3C has been working on a specification that brings together CSS, SVG and JavaScript animation under a unified language without any need for external JavaScript libraries. The API is known as Web Animations and works great for the kind of dynamic animations for which CSS is less suited. You can read this helpful introduction to the Web Animations API (AAPI) by Dudley Storey here on your very own SitePoint.

Work on the Web Animations API has been going on at a sustained pace and a polyfill is also available for browsers that don’t provide native support for the API.

All this sounds good and I actively encourage experimenting with the WAAPI. However, at the time of writing, browser support is sketchy and the specification might still change in the future. So, if the WAAPI is not a good fit for your project right now, you can turn to JavaScript animation libraries to get the job done.

Animation Libraries for Dynamic DOM Animation

There is a wide choice of JavaScript animation libraries for you to try out. At the time of writing GreenSock, also known as GSAP (GreenSock Animation Platform), and Velocity.js are among the big players.

Both are fantastic, user-friendly tools and I will talk about them in subsequent articles. However, I’d like to kick off this series with Anime.js, a new JavaScript animation library that’s been gaining some significant traction.

Anime’s Main Features

The name Anime is Japanese for hand-drawn or computer animation (Japanese: アニメ)

Anime.js JavaScript animation library logo

As for its features, Anime.js…

is a flexible yet lightweight JavaScript animation library. It works with CSS, Individual Transforms, SVG, DOM attributes and JS Objects.

Anime.js supports the following browsers:

  • Chrome
  • Safari
  • Opera
  • Firefox
  • Internet Explorer 10+

With All Animation Libraries Available, Why Anime?

The answer to this question is best left to Anime’s author as he explains why he came up with Anime.js when there’s something as powerful as GSAP around:

GSAP can do a lot more than Anime. But it’s also way more heavy. My goal with this library was to keep the API simple as possible, focus on the things I really need (multiple timings, easings, playback controls…) while keeping the code super lightweight (9KB minified).

Hacker News

In short, for dynamic animations of HTML and SVG elements which don’t require all of the features GSAP and other big libraries offer out of the box, Anime.js can be an excellent option for your project.

How to Use Anime.js

In what follows I have provided a few live samples to illustrate a basic use of Anime.js. Most animations will run a bit slowly for demonstration purposes.

Including Anime.js is not different from including jQuery or any other familiar JavaScript library.

Download the .zip file from the library’s project’s page on GitHub, extract the files and add anime.min.js using <script> tags in your html document:

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

Alternatively, you can use npm or bower:

npm install animejs
bower install animejs

Adding One Animation to a Single Element: Bouncing Ball

Once you’ve got Anime set up in your project, you can get started with the simplest kind of animation: just one element, a ball, bouncing up and down.

The first step is to call anime passing an object with a bunch of details about the animation. Here’s the basic structure:

var bouncingBall = anime({

  //code here
	
});

Next, you need to flesh out the object above with some instructions on what to animate, the kind of animation, its duration, etc.

var bouncingBall = anime({
  targets: '.ball',
  translateY: '50vh',
  duration: 300,
  loop: true,
  direction: 'alternate',
  easing: 'easeInCubic'
});

The targets property tells Anime which element you want to animate. Here you can use a CSS selector like I did in the example above, or any of the following:

  • DOM element, e.g., document.querySelector('.ball')
  • Nodelist, e.g., document.querySelectorAll('.ball')
  • JavaScript object, e.g., {elementName: 'ball'}
  • JavaScript array, e.g., ['.ball']

If your targets property has more than one value, that is, you intend to apply your animation to more than one element, you can use an array as your data structure, like so:

var bouncingBall = anime({
  targets: ['.ball', '.kick'],
  //rest of the code
});

The second property in the example above moves the ball element vertically with translateY, which should be familiar to those using CSS. Tiffany Brown and others recommend using translate and scale to move elements and change their dimensions respectively, as opposed to targeting elements’ position properties or their width and height. This aids the performance and quality of the animation by avoiding browser reflows.

Next in the list of properties in the above animation snippet is the duration property. This tells Anime how long you want the animation to last. If you have more than one animation taking place at different times, delay is another useful property.

The loop property tells Anime how many times you want the animation to take place. Its default value is false, which makes the animation run just once. You can have your animation run indefinitely by changing this value to true, or have it run a precise number of times by setting this property to the desired number.

The direction property is also present in CSS animations and Anime allows you to set it to any of the values of its CSS counter-part: normal, reverse and alternate. This last value alternates between the normal direction of the animation and its reverse, which seems to work great for a bouncing ball.

Finally, the above code specifies an easing property for your animation. Is the rate of change constant? Perhaps the animation starts slowly and speeds up towards the end? Is there a bounce in the final part? The right easing value is a crucial ingredient of a polished and effective animation.

You can find out all the easing functions you can use with Anime with this simple snippet:

console.log(anime.easings);

Adding a Second Animation to the Bouncing Ball

Let’s say you want the bouncing ball to get squashed a bit as it hits the bottom of its container. You can do this with Anime by adding specific animation parameters in the form of a JavaScript object. Using the bouncing ball example, here’s how you can achieve the desired effect:

var bouncingBall = anime({
  targets: '.ball',
  translateY: '50vh',
  duration: 300,
  loop: true,
  direction: 'alternate',
  easing: 'easeInCubic',
  //new code
  scaleX: {
    value: 1.05,
    duration: 150,
    delay: 268
  }
});

The code above adds a new property, scaleX, to increase the ball’s width and sets its value in the form of an object literal with specific keys that you can use to control your animation.

The value key lets you control the element’s width as you scale it on its horizontal axis, while the duration and delay keys let you set how long the animation is going to last and when it’s going to start with respect to the previous animation respectively.

See the Pen Bouncing Ball with Anime JS by SitePoint (@SitePoint) on CodePen.

If you inspect the code using you favorite browser’s dev tools, you’ll see how Anime animates the element by injecting an inline <style> tag and dynamically updating the values of the CSS transform property:

How Anime.js Updates the DOM

Animating Two Elements in Succession: Kicking a Ball

The sample code below shows one way in which you can animate two elements, in this case two images, in succession: the second animation starts once the first animation has completed.

var kickBall = anime({
  targets: '.kick',
  scale: 1.2,
  duration: 300,
  easing: 'easeInCubic',
  complete: function() {
    anime({
      targets: '.ball',
      translateX: '70vw',
      scale: 1.5,
      easing: 'easeOutBounce',
      delay: 150
    });
  }
});

The ball animates only after it has been kicked. With Anime.js you can stagger the animations using the complete() method, which in this case contains a second object with instructions to animate the ball element.

See the Pen Animate Two Elements with Anime JS by SitePoint (@SitePoint) on CodePen.

Image courtesy of Pixabay.com

Of course, it takes a few keyframes and a fancy cubic bezier function to quickly approximate this kind of static animation in CSS. In this case, you won’t need any JavaScript at all and will end up with a smooth animation that runs natively in the browser.

Here’s the CSS-only demo:

See the Pen Animating Two Images with CSS by SitePoint (@SitePoint) on CodePen.

Playing, Pausing and Restarting an Animation

Anime.js lets you control when to play, stop and restart your animations with the .play(), .pause(), and .restart() methods. You can also find a specific point along the course of your animation with the .seek() method.

For instance, here’s how you can control the kicking ball animation with the play button.

//Animating the kick
var kickBall = anime({
  targets: '.kick',
  scale: 1.2,
  duration: 300,
  delay: 100,
  easing: 'easeInCubic',
  autoplay: false
});

//Animating the ball
var movingBall = anime({
  targets: '.ball',
  translateX: '70vw',
  scale: 1.5,
  easing: 'easeOutBounce',
  delay: kickBall.duration + 100,
  autoplay: false
});

/* Playing the animation 
when clicking the play button */
btnPlay.addEventListener('click', function(e) {
  e.preventDefault();
  kickBall.play();
  movingBall.play();
});

A few things to note about the snippet above:

  • to be able to control both the kick and the ball using a button, I created two separate objects. I could have nested the animation of the ball inside that of the kick, but my experience has been that the button could only control the main animation, i.e., the kick, not the nested one;
  • to prevent your animations from running on page load, it is necessary to set autoplay to false;
  • finally, it’s just a matter of calling the .play() method on the kickBall and movingBall objects to have them behave exactly as you want.

See the Pen Anime JS with Buttons by SitePoint (@SitePoint) on CodePen.

Although replicating the behavior of the play and pause buttons is quickly done using the CSS animation-play-state property and a tiny bit of JavaScript, the same does not hold if you want to restart your animation once it’s finished running or retrace an exact point along its course.

Animating Inline SVG Attributes With Anime.js

This last demo illustrates how you can animate attributes of an inline SVG graphic, in this case the graphic represents a cute cat playing with a ball.

The demo uses CSS classes on the various paths and shapes that make up the SVG graphic, so that it’s easy to target them in the code.

This is how you can animate the cat’s eyes:

var movingEyes = anime({
  targets: ['.inner-left-eye', '.inner-right-eye'],
  cy: 400,
  duration: 500,
  delay: function(el, index) {
    var singleDelay = index === 0 ? 300 : index * 500;
    return singleDelay;
  },
  autoplay: false
});

The code above lowers the cat’s eyes by modifying the value of the cy attribute of the circle shapes that make up the cat’s pupils.

If you notice, the eyes move in succession. I’ve done this on purpose to show you one more cool way in which you can stagger animations with Anime.js. The delay property can be a number but also a function. When you use a function as in the code above, you have programmatic control over the starting time of your animation. The function tells Anime that if the element you want to animate is the first one (at the 0 position in the targets array), i.e., the left eye, then the animation has a 300ms’ delay, otherwise the element has a delay that results from the index number (i.e., 1) multiplied by 500ms with respect to the completion of the previous animation.

See the Pen Anime JS SVG Example by SitePoint (@SitePoint) on CodePen.

SVG graphic adapted from original on Pixabay.com

Conclusion

I opened this article with a brief look at how animation is used on the web, followed by a discussion on when you could consider JavaScript versus CSS for animation, and a cursory reference to the Web Animations API.

I also introduced Anime.js, the first animation library in this series, by illustrating some of its features and putting it to work on CodePen.

Overall, I’ve found Anime.js fun to work with: its features cover a fair number of use cases, its syntax is quite straightforward, and it lets you create smooth, beautiful animation effects.

For those who first approach it, I must say the README.md file on GitHub is the only documentation available at this point.

That said, you can find some great answers to some of your questions in the project’s GitHub issues section, which seems to be closely monitored by Anime’s creator Julian Garnier.

Also, you can learn more on how to use the library by digging into the code of some of the amazing demos that use Anime as their animation engine:

If you have used Anime.js and would like to share your experience or would like to suggest your favorite animation library for this series, hit the comment box below with your message.

Sponsors