How to create a checkmark animation with anime-js.

Animations can be great if used in appropriate contexts. They create moments of charm and, when correctly used, they help to increase the user’s understanding of the UI. What once was a big no-no, using animations at all, has now become more or less the standard when building new web pages. Highlighting certain state transitions, changes and give feedback for certain actions are generally good places to use animations.

Creating animations with web technologies can be tricky though as there is a lot to consider and many ways to go about creating them. In this post I’ll use anime.js (アニメ, a-ni-me in Japanese katakana, referring to animations among other things), a great and very versatile Javascript animation library written by Julian Garnier. It easily lets you create and manage animations in a really compact way. There are loads of javascript animation libraries out there and I urge you to try to find the one that fits your needs. I’ve grown fond of anime.js since it has a very compact syntax at the same time as being very flexible. With anime.js I’ll create a simple and flat check mark animation useful for the case where the user completes an action which we, from a UX perspective, want to highlight. Let’s start out with the end result and break it down in steps to be separately discussed. Here is the complete animation:

The animation is simple, fluid and it basically consists of a circle and a check mark, a white stroke. To create such a circle I would normally use the CSS border-radius rule. The border-radius is way more convenient (less code) than using SVGs. However, in this case, as I’ll later on want to add a check mark as a stroke, I might as well also do the circle in SVG too. SVGs are, by the way, becoming increasingly popular in 2017 and no wonder why. They are small when sent through the network, they usually compress to a fraction of their original size and they are always crisp (almost) regardless of their zoom level or whether they’re scaled or not. Below is what the code, SVG inline style, look like to draw a filled circle:

<svg class="checkmark"
xmlns="http://www.w3.org/2000/svg"
width="32"
height="32"
viewBox="0 0 32 32">
<circle class="circle"
cx="16"
cy="16"
r="16"
fill="#0c3"/>
</svg>

This is pretty straightforward, a green (#0c3) circle drawn around its center point at (16, 16) with the radius (r) of 16 pixels. This circle is drawn inside a 32 by 32 pixels svg node in a view (the viewBox) that spans from (0, 0) to (32, 32). Here is the rendered result:

To make something happen let’s add the first animation step, scaling the circle from nothing to its full size. To do so we need two things: 1. A reference to the circle, in this case, it’s class name, and 2. An anime.js timeline. I’ll use a timeline here since I later on want to add more animation steps. You actually don’t need to use timelines as you can directly create an anime animation calling the anime constructor. One of the key rules, creating good animations, is to use the principle of delay and offset. This is where you want to spread out the different parts of your animation to make the whole thing become a bit more fluid. Think of the whole thing as falling dominos in pretty patterns. Bricks don’t fall all at once but rather one by one. Here is where the timeline comes in handy as it gives me more fine-grained control when different parts of the animation should take place. Scaling the outer SVG node will also scale everything inside it, which in turn will add to effect as the stroke will also be up-scaled. Here is what the snippet of javascript that does the scaling looks like:

var checkTimeline = anime.timeline({ autoplay: true, direction: 'alternate', loop: true });
checkTimeline
.add({
targets: '.checkmark',
scale: [
{ value: [0, 1], duration: 600, easing: 'easeOutQuad' }
]
})

The key things here are the target (targets key) taking, the SVG node (.checkmark) and the action (scale key) scaling the circle for a period of 600ms. This is basically what does all the magic. Looping, alternating and autoplay are just configurations that suits well for this article and when crafting the animation. In a real UI scenario it would run once and be over with.

Here is the result so far:

Selecting the duration is also an artform in itself. On one hand you don’t want keep the user waiting as it will degrade the overall experience making the UI feel sluggish. On the other hand you don’t want things to happen too fast as you might loose or distract the user. I am using a longer period (slightly less than a second) in this example. This period will probably be a bit too long to keep the user waiting for in a shipped version. It’s quite fine when developing the animation but in production you’d want your UI to be snappy. The rule of thumb here is to start out slow and then increase the speed of the whole animation once you’ve fine-tuned all the different parts. The material design guidelines has a quite good section on animation speed here: duration & easing

Using easing on animations has become the standard anno 2017 as it makes animations more realistic and delightful. It is worthwhile to try out different kinds of easings for different kinds of animations. Selecting the right easing depends on the object, its shape, the distance traveled, the context it’s used in, etc. The standard CSS easing is using what’s called “in” and “out” easing, starting slow, doing most of the change centered to the middle to slow down in the end again. In this animations I would like the object to only emphasize its deacceleration, when scaling up, which makes it more appropriate to use an ease-out (without the “in”) easing.

Now for the stroke! Strokes are much more complicated compared to circles as they are typically constructed by SVG paths. These are in turn are defined by the SVG d attribute, which, at a first glance, might look like encrypted or garbled data. The d attribute consists of a set of rules, more in detail described here: The d attribute. I almost always use an editor, Inkscape, to draw these shapes as it gives me more degrees of freedom to quickly alter the SVG. In this case we’re fine with a simple white line consisting of three points. I also use linecap of 2.5px to get rounded corners.

Just a word about design here: Be sure to adhere to your design principles and be consistent throughout the your project. Consistency is one the most important and profound design principles there is. If you use rounded corners throughout your UI, do so as well in your animations. If not, then go with squared corners or what have you. The same goes for colors (your palette), spacing, etc.

Using Inkscape to create the stroke

and in code:

<path class="check"
d="M9 16l5 5 9-9"
fill="none"
stroke="#fff"
stroke-width="2.5"
stroke-linecap="round">

Let’s run the same animation again to see where we’re at:

Pretty close. Ok, for the last step let’s offset and draw the stroke. Here I’ll use the SVG dash technique to draw the line. The anime.js library has a nice helper function (anime.setDashoffset) to calculate the line length, which we can use to mimic drawing a line with the dash technique. If you have a deeper interest for the inner working of this technique it is outlined in this article: How SVG line animation works. The article also has some links to other good articles about how to create this part of the animation. The code looks like this:

checkTimeline
.add({ ... }) /* Previous steps */
.add({
targets: '.check',
strokeDashoffset: {
value: [anime.setDashoffset, 0],
duration: 700,
delay: 200,
easing: 'easeOutQuart'
}

Once again I use targets and action to animate. The above sets the animation’s start value to the path’s full offset as calculated with the helper function. This part of the animation starts out with a full offset (no part of the path visible) and animates the line to no offset (path fully displayed). I also introduced a delay for fluidity as covered above.

Last but not least I add an translation to the checkmark stroke to make it bit more balanced (centered). As a last step I translate (move) the checkmark a few pixels sideways and vertically to always keep it somewhat in the center of the circle.

That’s it! Below is the code. Enjoy creating animations with anime.js and the best of luck with your animations!

Show your support

Clapping shows how much you appreciated Mikael Ainalem’s story.