Thursday, 22 January 2015

Animating Without jQuery

There’s a false belief in the web development community that CSS animation is the only performant way to animate on the web. This myth has coerced many developers to abandon JavaScript-based animation altogether, thereby (1) forcing themselves to manage complex UI interaction within style sheets, (2) locking themselves out of supporting Internet Explorer 8 and 9, and (3) forgoing the beautiful motion design physics that are possible only with JavaScript.

Reality check: JavaScript-based animation is often as fast as CSS-based animation — sometimes even faster. CSS animation only appears to have a leg up because it’s typically compared to jQuery’s $.animate(), which is, in fact, very slow. However, JavaScript animation libraries that bypass jQuery deliver incredible performance by avoiding DOM manipulation as much as possible. These libraries can be up to 20 times faster than jQuery.

So, let’s smash some myths, dive into some real-world animation examples and improve our design skills in the process. If you love designing practical UI animations for your projects, this article is for you.

Why JavaScript?

CSS animations are convenient when you need to sprinkle property transitions into your style sheets. Plus, they deliver fantastic performance out of the box — without your having to add libraries to the page. However, when you use CSS transitions to power rich motion design (the kind you see in the latest versions of iOS and Android), they become too difficult to manage or their features simply fall short.

Ultimately, CSS animations limit you to what the specification provides. In JavaScript, by the very nature of any programming language, you have an infinite amount of logical control. JavaScript animation engines leverage this fact to provide novel features that let you pull off some very useful tricks:

  • cross-browser SVG support,

  • physics-based loader animations,

  • timeline control,

  • Bezier translations.

Note: If you’re interested in learning more about performance, you can read Julian Shapiro’s “CSS vs. JS Animation: Which Is Faster?” and Jack Doyle’s “Myth Busting: CSS Animations vs. JavaScript.” For performance demos, refer to the performance pane in Velocity’s documentation and GSAP’s “Library Speed Comparison” demo.

Velocity and GSAP

The two most popular JavaScript animation libraries are Velocity.js and GSAP. They both work with and without jQuery. When these libraries are used alongside jQuery, there is no performance degradation because they completely bypass jQuery’s animation stack.

If jQuery is present on your page, you can use Velocity and GSAP just like you would jQuery’s $.animate(). For example, $element.animate( opacity: 0.5 ); simply becomes $element.velocity( opacity: 0.5 ).

These two libraries also work when jQuery is not present on the page. This means that instead of chaining an animation call onto a jQuery element object — as just shown — you would pass the target element(s) to the animation call:

/* Working without jQuery */

Velocity(element, opacity: 0.5 , 1000); // Velocity, 1, opacity: 0.5 ); // GSAP

As shown, Velocity retains the same syntax as jQuery’s $.animate(), even when it’s used without jQuery; just shift all arguments rightward by one position to make room for passing in the targeted elements in the first position.

GSAP, in contrast, uses an object-oriented API design, as well as convenient static methods. So, you can get full control over animations.

In both cases, you’re no longer animating a jQuery element object, but rather a raw DOM node. As a reminder, you access raw DOM nodes by using document.getElementByID, document.getElementsByTagName, document.getElementsByClassName or document.querySelectorAll (which works similarly to jQuery’s selector engine). We’ll briefly work with these functions in the next section.

Working Without jQuery

(Note: If you need a basic primer on working with jQuery’s $.animate(), refer to the first few panes in Velocity’s documentation.)

Let’s explore querySelectorAll further because it will likely be your weapon of choice when selecting elements without jQuery:

document.querySelectorAll("body"); // Get the body element
document.querySelectorAll(".squares"); // Get all elements with the "square" class
document.querySelectorAll("div"); // Get all divs
document.querySelectorAll("#main"); // Get the element with an id of "main"
document.querySelectorAll("#main div"); // Get the divs contained by "main"

As shown, you simply pass querySelectorAll a CSS selector (the same selectors you would use in your style sheets), and it will return all matched elements in an array. Hence, you can do this:

/* Get all div elements. */
var divs = document.querySelectorAll("div");

/* Animate all divs at once. */

Velocity(divs, opacity: 0.5 , 1000); // Velocity, 1, opacity: 0.5 ); // GSAP

Because we’re no longer attaching animations to jQuery element objects, you may be wondering how we can chain animations back to back, like this:

$element // jQuery element object
.velocity( opacity: 0.5 , 1000)
.velocity( opacity: 1 , 1000);

In Velocity, you simply call animations one after another:

/* These animations automatically chain onto one another. */
Velocity(element, opacity: 0.5 , 1000);
Velocity(element, opacity: 1 , 1000);

Animating this way has no performance drawback (as long as you cache the element being animated to a variable, instead of repeatedly doing querySelectorAll lookups for the same element).

(Tip: With Velocity’s UI pack, you can create your own multi-call animations and give them custom names that you can later reference as Velocity’s first argument. See Velocity’s UI Pack documentation for more information.)

This one-Velocity-call-at-a-time process has a huge benefit: If you’re using promises with your Velocity animations, then each Velocity call will return an actionable promise object. You can learn more about working with promises in Jake Archibald’s article. They’re incredibly powerful.

In the case of GSAP, its expressive object-oriented API allows you to place your animations in a timeline, giving you control over scheduling and synchronization. You’re not limited to one-after-the-other chained animations; you can nest timelines, make animations overlap, etc:

var tl = new TimelineMax();
/* GSAP tweens chain by default, but you can specify exact insertion points in the timeline, including relative offsets. */
.to(element, 1, opacity: 0.5 )
.to(element, 1, opacity: 1 );

Animating Without jQuery

No comments:

Post a Comment