In this article, I’ll go through what considerations I made, what to look out for and present you with some of the most popular libraries available. I’ll go through some real-world examples with you to illustrate my points, and in the end, hopefully, you’ll be better equipped than me when I first had to choose an animation library.
Your mileage with this advice may vary, of course. Everything I’m sharing here is specific to a thing I wanted to build. Your project may have completely different requirements and priorities and that’s OK. I think what’s important here is getting a first-hand account of thinking like a front-end developer with a particular goal.
Here’s the goal
Before we get into any decision-making let’s take a look at the sorts of animations I needed to make in this CSS-Tricks-ified version of the game:
Pretty sweet, right? There’s nothing exactly trivial about these animations. There’s a lot going on – sometimes simultaneously – and a lot to orchestrate. Plus, a majority of the animations are triggered by user interactions. So, that left me with a few priorities heading into my decision:
- Smooth animations: The way animations are applied can have a big impact on whether they run smoothly, or display a little choppiness.
- Performance: Adopting any library is going to add weight to a project and I wanted my game to be as lean as possible.
- Convenience: I wanted a nice, clean syntax that makes it easier to write and manage the animations. I’d even trade a little extra convenience for a small performance cost if it allows me to write better, more maintainable code. Again, this bodes well for a designer-turned-developer.
- Browser support: Of course I wanted my game to work on any modern browser using some form of progressive enhancement to prevent completely borking legacy browsers. Plus, I definitely wanted some future-proofing.
That’s what I took with me as I went in search of the right tool for this particular job.
Let’s see how a simple sequenced animation looks in CSS and compare it to jQuery, which has plenty of built-in animation helpers:
The animations look the same but are created differently. To make the CSS animation, first, we have to define the keyframe animation in our CSS and attach it to a class:
.card.move animation : move 2s; @keyframes move 0% left: 0 50% left: 100px 100% left: 0
var cardElement = document.getElementsByClassName("card"); var statusElement = document.getElementsByClassName("status"); cardElement.classList.add("move"); statusElement.innerHTML = "Animating" var animationEndCallback = function() cardElement.classList.remove("move"); statusElement.innerHTML = "Inactive" cardElement.addEventListener("webkitAnimationEnd", animationEndCallback); cardElement.addEventListener("oAnimationEnd", animationEndCallback); cardElement.addEventListener("antionend", animationEndCallback);
Having things happen in different places might be fine in a simple example like this, but it can become very confusing once things get a bit more complex.
Compare this to how the animation is done with jQuery:
$(".status").text("Animating") $( ".card" ).animate( left: "100px" , 1000); $( ".card" ).animate( left: 0 , 1000, function() $(".status").text("Inactive") );
Here, everything happens in the same place, simplifying things should make the animations grow more complex in the future.
An active community was critical to me since I needed a place to ask for help, and I did not want to use a library that might later be abandoned. I considered this as part of my convenience requirements.
Sequencing animations and callbacks
Once I had my choices narrowed down, the next step was to implement a complex animation using my two libraries. A recurrent animation in a solitaire game is that of a card moving somewhere and then turning over, so let’s see how that looks:
Both animations look great! They’re smooth, and implementing both of them was pretty straightforward. Both libraries had a timeline function that made creating sequences a breeze. This is how the implementation looks in AnimeJS:
var timeline = anime.timeline( begin: function() $(".status").text("Animating") , complete: function() $(".status").text("Inactive") ); timeline.add( targets: '.card', left: [0, 300], easing: 'easeInOutSine', duration: 500 ).add( targets: '.card .back', rotateY: [0, 90], easing: 'easeInSine', duration: 200 ).add( targets: '.card .front', rotateY: [-90, 0], easing: 'easeOutSine', duration: 200 )
timeline() function comes built-in with callbacks on beginning and ending the animation, and creating the sequence is as easy as appending the sequential animations. First, I move the card, then I turn my back-image 90 degrees, so it goes out of view, and then I turn my front-image 90 degrees, so it comes into view.
The same implementation using GSAP’s
timeline() function looks very similar:
var timeline = gsap.timeline( onStart: function() $(".status").text("Animating") , onComplete: function() $(".status").text("Inactive") ); timeline.fromTo(".card", left: 0 , duration: 0.5, left: 300 ).fromTo(".card .back", rotationY: 0 , rotationY: 90, ease: "power1.easeIn", duration: 0.2 ).fromTo(".card .front", rotationY: -90 , rotationY: 0, ease: "power1.easeOut", duration: 0.2 )
The main difference between Anime and GSAP appears to be the syntax, where GSAP might be a little more elaborate. I was stuck with two great libraries that had very similar functionality, were able to deal with complex animation, and had a thriving community. It seemed like I had a tie race!
So, what made me choose one library over the other?
I was very concerned about how the library would act under pressure. Having laggy animations in a game like Solitaire can greatly impact how fun it is to play the game. I knew I would not be able to fully see how the library performed before I created the game. Luckily, GSAP had made a stress test that compared different animation libraries to each other, including Anime.
Looking at that, GSAP certainly looked to be the superior library for dealing with loads of complex animations. GSAP was giving me upwards of 26 frames per second on a heavy animation that Anime was only able to top out at 19. After reading up on GSAP more and looking into their forums, it became clear that performance was of the highest priority to the guys behind GSAP.
And even though both GSAP and Anime have been around for a while, Anime’s repo has been sitting somewhat dormant a couple of years while GSAP had made commits in the past couple of months.
I ended up using GSAP and haven’t regretted my decision!
How about you? Does any of this square with how you evaluate and compare front-end tooling? Are there other priorities you might have considered (eg accessibility, etc.) in a project like this? Or do you have a project where you had to pare down your choices from a bunch of different options? Please share in the comments because I’d like to know!
Oh, and if you want to see how it looks when animating a whole deck of cards, you can head over to my site and play a game of Solitaire. Have fun!