- CSS animation workflow
- Code technique: Separate styling from logic
- Code technique: Organize sequenced animations
- Code technique: Package your effects
- Design techniques
- Wrapping up
Code technique: Separate styling from logic
The first technique has profound workflow benefits, especially for teams.
Standard approach
In jQuery animation, it’s common to animate CSS classes onto elements using the UI add-on plugin (jQueryUI.com). When the module is loaded, jQuery’s addClass() and removeClass() functions are upgraded with animation support. For example, let’s say you have a CSS class defined in a stylesheet as follows:
.fadeInAndMove { opacity: 1; top: 50px; }
You can then animate the CSS properties of that class (opacity and top in this case) onto the target element along with a specified duration:
// Animate the properties of the .fadeInAndMove class over a 1000ms duration $element.addClass("fadeInAndMove", 1000);
The more common implementation of jQuery animation consists of inlining the desired animation properties within an $.animate() call, which uses the syntax demonstrated in Chapter 1, “Advantages of JavaScript Animation”:
$element.animate({ opacity: 1, top: 50 }, 1000);
Both implementations produce the same result. The difference is their separation of logic: The first implementation delegates the styling rules to a CSS stylesheet, where the rest of the page’s styling rules reside. The second mixes styling rules with the JavaScript logic responsible for triggering them.
The first approach is preferable due to the organizational cleanliness and flexibility gained by knowing where to look to make the appropriate style or logic changes to your code. CSS stylesheets exist for a reason; seasoned developers do not inline CSS into their HTML. That would conflate the purposes of HTML (structure) and CSS (styling), and make a site considerably more difficult to maintain.
The value of logic separation is further pronounced when working in a team environment, in which it’s common for developers and designers to bump heads while trying to edit the same file at the same time.
Optimized approach
With the review of standard methods out of the way, let’s look at the optimized approach. It’s just as beneficial—and often the best methodology for JavaScript-centric animation workflows—to shift animation styling logic into a dedicated JavaScript file (for example, a style.js) rather than a dedicated CSS stylesheet. Sounds weird, right? Perhaps, but it works brilliantly. This technique leverages plain old JavaScript objects to help you organize your animation code.
For example, your style.js file might look like this:
// This object is a parallel to the CSS class defined in the previous code example var fadeIn = { opacity: 1, top: "50px" };
In your script.js, which is the primary JavaScript file that controls animation logic, you would then have:
// Pass our named properties object into Velocity $element.velocity(fadeIn, 1000);
To recap, in your style.js, you’ve defined a JavaScript object that’s populated with the CSS properties you want to animate. This is the same object that’s then passed into Velocity as a first argument. You’re not doing anything fancy here—just saving objects to named variables, then passing those variables into Velocity instead of the raw objects themselves.
The benefit of switching from CSS to JavaScript to segregate logic is that your style.js file is uniquely capable of defining animation options—not just animation properties. There are many ways to specify an option: one is to assign two member properties to a parent animation object to which you assign an expressive name. The first property on the object defines the animation’s properties; the second defines its options.
In this case, your style.js file would look like this:
var fadeIn = { // p is for "properties" p: { opacity: 1, top: "50px" }, // o is for "options" o: { duration: 1000, easing: "linear" } };
In the script.js file, you’d have:
// Pass in our clean and re-usable animation objects $element.velocity(fadeIn.p, fadeIn.o);
Pretty and clean, right? Someone skimming it would understand its purpose, and would know where to look to modify its properties—the style.js file. Further, the purpose of this animation is immediately evident: because you’ve named the animation object appropriately, you know that the code serves to fade an object into view. You no longer have to mentally parse animation properties to assess the purpose of the animation.
This approach discourages you from arbitrarily setting options for each individual animation on a page since there’s now a bank of premade animation objects you can easily pull from. This results in leaner code and more consistent motion design. Consistency, as you learned in the previous chapter, is a key component of great UX.
But the best part is that this approach lends itself perfectly to organizing your animation variations together. For example, if you typically fade button elements into view with a duration of 1000ms, but you fade modal windows into view with a duration of 3000ms, you can simply split your options object into two appropriately named variations:
var fadeIn = { p: { opacity: 1, top: "50px" }, // Options object variation #1 uses a fast duration oFast: { duration: 1000, easing: "linear" }, // Variation #2 uses a slower duration oSlow: { duration: 3000, easing: "linear" } }; // Animate using the fast duration. $button.velocity(fadeIn.p, fadeIn.oFast); /* Animate using the slow duration. */ $modal.velocity(fadeIn.p, fadeIn.oSlow);
Alternatively, you could nest “fast” and “slow” objects as children of a singular o options object. The choice of which implementation to use is based on your personal preference:
var fadeIn = { p: { opacity: 1, top: "50px" }, o: { fast: { duration: 1000, easing: "linear" }, slow: { duration: 3000, easing: "linear" } } }; // Animate using the fast duration. $button.velocity(fadeIn.p, fadeIn.o.fast); /* Animate using the slow duration. */ $modal.velocity(fadeIn.p, fadeIn.o.slow);
If this seems like too much overhead, and if you have few enough lines of JavaScript to justify simply inlining all your animation logic, then don’t feel like a bad developer for skipping this approach altogether. You should always use whichever degree of abstraction best suits the scope of your project. The takeaway here is simply that animation workflow best practices do exist if you find yourself needing them.