//

ANIMATION SPEED IN JAVASCRIPT AND CSS

In this article, we go through how JavaScript-based DOM animation libraries, such as Velocity.js and GSAP, are more efficient than jQuery and CSS-based animation libraries. We will discuss how those libraries work, where to use them and what other alternatives are out there for animation.

jQuery

Let's start with the basics: JavaScript and jQuery are falsely conflated. JavaScript animation is fast. jQuery slows it down. Why? obvious, despite jQuery being tremendously powerful, it was never the goal of its designers for jQuery to be an efficient animation engine:

Note that layout thrashing is what causes stuttering at the start of animations, garbage collection is what causes stuttering during animations, and the absence of RAF is what generally produces low frame rates.

DOM queries and DOM updates

Queries that take place after an update force the browser to recalculate the page’s computed style data (while considering the new update’s effects). This produces significant overhead for animations that are running over tiny intervals of just 16ms.

Avoiding layout thrashing consists of simply batching together DOM queries and DOM updates:

var currentTop, 
    currentLeft; 

/* With layout thrashing. */ 
currentTop = element.style.top; /* QUERY */ 
element.style.top = currentTop + 1; /* UPDATE */ 

currentLeft = element.style.left;  /* QUERY */ 
element.style.left = currentLeft + 1; /* UPDATE */ 

/* Without layout thrashing. */ 
currentTop = element.style.top; /* QUERY */ 
currentLeft = element.style.left; /* QUERY */ 

element.style.top = currentTop + 1; /* UPDATE */ 
element.style.left = currentLeft + 1; /* UPDATE */ 

Implementing RAF doesn’t require a massive refactoring to your existing codebase. Let’s compare the basic implementation of RAF against that of setInterval:

var startingTop = 0; 

/* setInterval: Runs every 16ms to achieve 60fps (1000ms/60 ~= 16ms). */ 
setInterval(function() { 
  /* Since this ticks 60 times a second, we divide the top property's 
     increment of 1 unit per 1 second by 60. */ 
  element.style.top = (startingTop += 1/60); 
}, 16); 

/* requestAnimationFrame: Attempts to run at 60fps based on whether the 
   browser is in an optimal state. */ 
function tick () { 
  element.style.top = (startingTop += 1/60); 
} 

RAF makes a huge boost to animation performance that you could make with a single change to your code.

CSS Transitions

CSS transitions unlike jQuery, offloads animation logic to the browser itself, which makes it efficient by

  • optimizing DOM interaction and memory consumption to avoid stuttering,
  • leveraging the principles of RAF under the hood and
  • forcing hardware acceleration (leveraging the power of the GPU to improve animation performance).

The reality, however, is that these optimizations can also be performed directly within JavaScript. GSAP has been doing it for years. Velocity.js, a new animation engine, not only leverages these same techniques but also goes several steps beyond -- as we'll explore shortly.

The JavaScript animation can be faster than CSS animation libraries:

Let's find out the weaknesses of the CSS animation libraries.

  • Transitions' forced hardware acceleration intensifies GPU's, resulting in stuttering and banding in high-stress situations. These effects are exacerbated on mobile devices. (Specifically, the stuttering is a result of the overhead that occurs when data is transferred between the browser's main thread and its compositor thread. Some CSS properties, like transforms and opacity, are immune to this overhead.) Adobe elaborates on this issue here.
  • Transitions do not work below Internet Explorer 10, causing accessibility problems for desktop sites since IE8 and IE9 remain very popular.
  • Because transitions aren't natively controlled by JavaScript (they are merely triggered by JavaScript), the browser does not know how to optimize transitions in sync with the JavaScript code that manipulates them.

JavaScript-based animation libraries can decide for themselves when to enable hardware acceleration, they inherently work across all versions of IE, and they’re perfectly suited for batched animation optimizations.

If you are exclusively developing for mobile and your animations consist solely of simple state changes, you will be better off using raw CSS transitions. In such circumstances, transitions are efficient and native that allow you to retain all animation logic inside your stylesheets and avoid bloating your page with JavaScript libraries. If you're designing intricate UI flourishes or are developing an app with a stateful UI, always use an animation library so that your animations remain efficient and your workflow remains manageable. One such library that does a great job at managing CSS transitions is Transit.

JavaScript Animation

So as you see, JavaScript can have the upper hand when it comes to performance. But exactly how much faster can JavaScript be?

Velocity

How exactly does JavaScript reach its high levels of performance? Below is a shortlist of optimizations that JavaScript-based animation is capable of performing:

  • Synchronizing the DOM → tween stack across the entirety of the animation chain in order to minimize layout thrashing.
  • Caching property values across chained calls in order to minimize the occurrence of DOM querying (which is the Achilles' heel of performant DOM animation).
  • Caching unit conversion ratios (e.g. px to %, em, etc.) across sibling elements in the same call.
  • Skipping style updating when updates would be visually imperceptible.

Revisiting what we learned earlier about layout thrashing, Velocity.js leverages these best practices to cache the end values of an animation to be reused as the start values of the ensuing animation — thus avoiding querying the DOM for the element’s start values:

In the above example, the second Velocity call knows that it should automatically start with an opacity value of 1 and a top value of 50%.

The browser can perform most of these same optimizations itself, but it can limit the ability of the developer to do so. Hence why jQuery doesn't use RAF, browsers would never impose optimizations that have even a tiny chance of breaking spec or deviating from expected behaviour.

GSAP

Finally, let’s compare the two JavaScript animation libraries (Velocity.js and GSAP) against one another.

  • GSAP is a fast, richly-featured animation platform. Velocity is a lightweight tool for drastically improving UI animation performance and workflow.
  • GSAP requires a licensing fee for various types of businesses. Velocity is freely open-sourced via MIT license.
  • Performance-wise, GSAP and Velocity are similar in real-world projects.

Ideally, you should use GSAP when you require precise control over timing (e.g. remapping, pause/resume/seek), motion (e.g. bezier curve paths), or complex grouping/sequencing. These features are crucial for game development and certain niche applications, but are less common in web app UI’s.

Velocity.js

Referencing GSAP’s rich feature set is not to imply that Velocity itself is light on features. To the contrary. In just 7Kb when zipped, Velocity not only replicates all the functionality of jQuery’s $.animate(), but it also packs in colour animation, transforms, loops, easings, class animation, and scrolling.

In short, Velocity is the best of jQuery, jQuery UI, and CSS transitions combined.

Further, from a convenience viewpoint, Velocity uses jQuery's $.queue() method under the hood, and thus interoperates seamlessly with jQuery's $.animate(), $.fade(), and $.delay() functions. And, since Velocity's syntax is identical to $.animate()'s, none of your page’s code needs to change.

If you take a quick look at Velocity.js. At a basic level, Velocity behaves identically to $.animate():

At its most advanced level, complex scrolling scenes with 3D animations can be created — with merely two simple lines of code:

Summary

Head on over to VelocityJS.org to learn more.

So remember that there is about more than just choosing the right animation library.