Web Animation Using JavaScript Develop & Design (Develop and Design) by Julian Shapiro - 2015
Web Animation Using JavaScript Develop & Design (Develop and Design) by Julian Shapiro - 2015
WWW.PEACHPIT.COM
Acknowledgements
I would like to thank Yehonatan Daniv for providing support to Velocitys users on
GitHub, Anand Sharma for regularly inspiring me with his motion design work, and David
DeSandro for writing this books foreword. Id also like to thank Mat Vogels, Harrison
Shoff, Adam Singer, David Caplan, and Murat Ayfer for reviewing drafts of this book.
Contents
Foreword
Introduction
CHAPTER 1 ADVANTAGES OF JAVASCRIPT ANIMATION
Colors
Transforms
Using Velocity: Without jQuery (intermediate)
Wrapping up
CHAPTER 3 MOTION DESIGN THEORY
Sneaky images
Technique: Degrade animations on older browsers
Problem
Solution
Find your performance threshold early on
Wrapping up
CHAPTER 8 ANIMATION DEMO
Behavior
Code structure
Code section: Animation setup
Code section: Circle creation
Code section: Container animation
3D CSS primer
Properties
Options
Code section: Circle animation
Value functions
Opacity animation
Translation animation
Reverse command
Wrapping up
Index
Foreword
Its a special time when a developer first discovers jQuerys .animate(). I remember
trying to animate any part of the page that wasnt bolted to the main content. I created
accordions, fly-out menus, hover effects, scroll transitions, magical reveals, and parallax
sliders. Turning my websites from cold, static documents into moving, visual experiences
felt like I was reaching another level as a web designer. But it was just bells and whistles. I
realize now that for all the animation I added, I hadnt actually improved the user
experience of my websites.
All the same, it was thrilling. So what makes animation so exciting?
My apartment looks over downtown Brooklyn. I see people walk down the street.
Plumes from smokestacks billow up. Pigeons flutter to perch on a ledge. A construction
crane raises a section of a building. A single, heart-shaped balloon floats up into the
Brooklyn sky (corny, I know, but I literally saw this happen twice). Cars drive over the
Williamsburg Bridge. Clouds pass overhead.
The world is in motion.
This is how you expect the universe to work. Things move. Like the movements outside
my window, each one is a one-sentence story. Together they tell the larger story of what is
happening.
Yet this isnt how digital interfaces work. Those little stories are missing. When things
change, you have to fill in the story for yourself. When you press the Next button at an
ATM, the screen suddenly changes. Did it move forward successfully? Was there an error?
You have to read the screen again to interpret the results of your action. Utilizing motion
removes this leap of understanding between interactions. Motion inherently communicates
what has changed. Its like writing tiny stories between states.
When a slide transition takes you to the next screen, animation helps you better
understand what just happened. Wielding this power is what makes animation so thrilling.
Like layout, color, and typography, animation helps you shape and direct the user
experience. Animation is more than just making things move. Its designing more
effectively, and doing it thoughtfully.
Unfortunately, in the history of web animation, thoughtfulness hasnt always been the
highest priority. As developers, weve used Flash, animated GIFs, Java applets, marquee
tags, and, more recently, CSS, JavaScript, and SVG to create animation thats been, at
best, a level of polish or, at worst, a gimmick. The idea of creating animation thats both
high-performance and user-friendly is relatively new.
So its a good thing you have this book in front of you. Julian Shapiro is one of the
principal experts on animation on the web. In creating and supporting Velocity.js, he has
developed an intimate knowledge of all the quirks and advantages of using motion on
websites. Web Animation using JavaScript will give you not only the technical know-how
required to implement animation in your websites, but, more importantly, the insights
youll need to use animation effectively and craft compelling user experiences.
Animation libraries and technologies have made motion design more accessible than
ever. But not every developer abides by best practices. The past couple of years have seen
several trendy anti-patterns come and go. Scroll behavior has been hijacked. Mobile
navigation has been pushed into menus accessible only via gestures. While adding
animation is within the grasp of anyone who stumbles across .animate(), utilizing it to
improve the user experience is one of the hallmarks of a dedicated developer. This book
will help you become one of them.
David DeSandro
February 2015
Brooklyn, New York
David DeSandro is the founder of Metafizzy
and author/developer of Masonry and Isotope.
Introduction
In the early days of the web, animation was primarily used by novice developers as a
last-ditch effort to call attention to important parts of a page. And even if they wanted
animation to transcend its niche, it couldnt: browsers (and computers) were simply too
slow to deliver smooth web-based animation.
Weve come a long way since the days of flashing banner ads, scrolling news tickers,
and Flash intro videos. Today, the stunning motion design of iOS and Android
dramatically improves the user experienceinstead of detracting from it. Developers of
the best sites and apps leverage animation to improve the feel and intuitiveness of their
user interfaces. Animations rise to relevancy isnt just a by-product of improved
processing power; it reflects a better appreciation for best practices within the web
development community. The tools you use to make a website are now considered less
important than the quality of the resulting user experience. As obvious as this seems, it
wasnt always the case.
So, what makes animation in particular so useful? Whether its transitioning between
chunks of content, designing intricate loading sequences, or alerting the user what to do
next, animation complements text and layout to reinforce your sites intended behavior,
personality, and visual sophistication. Does your content bounce into view in a friendly
way, or does it whip across the screen? This is the domain of motion design, and the
decisions you make will establish the transcendent feeling of your app.
When users recommend your app to others, theyll often try to describe it with words
like sleek or polished. What they dont realize is that theyre mostly referring to the
motion design work thats gone into the interface. This inability of the layman to make the
distinction is precisely what great user interface (UI) designers strive for: animations that
reinforce the interfaces objectives but dont otherwise divert the users attention.
This book provides you with the foundation necessary to implement animation
confidently and in a way thats both technically maintainable and visually impactful.
Throughout, it considers the balance between enriching a page with motion design and
avoiding unnecessary flourishes.
Why is all of this so important? Why is it worth your time to perfect your transitions
and easing combinations? For the same reason that designers spend hours perfecting their
font and color combinations: refined products simply feel superior. They leave users
whispering to themselves, Wow, this is cool, right before they turn to a friend and
exclaim, You gotta see this!
Note
If youre unfamiliar with basic CSS properties, you should pick up an
introductory HTML and CSS book before reading this one.
Great performance
JavaScript and jQuery are falsely conflated. JavaScript animation is fast. jQuery slows it
down. Despite jQuery being tremendously powerful, it wasnt designed to be a highperformance animation engine. It has no mechanism to avoid layout thrashing, in which
a browser becomes overtasked with layout processing work while its in the process of
animating.
Further, because jQuerys code base serves many purposes beyond animation, its
memory consumption triggers garbage collections within the browser, causing animations
to stutter unpredictably. Lastly, due to decisions made by the jQuery team in the noble
pursuit of helping novice users avoid sabotaging their UI with bad code, jQuery forgoes
the recommended practice of using the requestAnimationFrame function, which
browsers make available to drastically improve frame rates for web animation.
JavaScript animation libraries that bypass jQuery entirely deliver fantastic performance
by streamlining their interaction with a page. One library of note, which well be using
throughout this book, is Velocity.js. Its lightweight, yet incredibly feature rich, and it
mirrors jQuerys animation syntax to help eliminate the learning curve.
This is a topic well explore in-depth in Chapter 7, Animation Performance. By
learning the nuances of browser rendering performance, youll gain a foundation on which
to build reliable animations for all browsers and devices, regardless of their individual
processing power.
Features
Speed is, of course, not the only reason to use JavaScriptits abundance of features is
equally as important. Lets run through a few of the notable animation features that are
exclusive to JavaScript.
Page scrolling
Page scrolling is one of the most popular uses for JavaScript-based animation. A recent
trend in web design is to create long webpages that animate new pieces of content into
view as the page is scrolled down.
JavaScript animation libraries, such as Velocity, provide simple functions for scrolling
elements into view:
Click here to view code image
$element.velocity(scroll, 1000);
This scrolls the browser toward the top edge of $element over a duration of 1000ms
using Velocitys "scroll" command. Notice that Velocitys syntax is nearly identical to
jQuerys $.animate() function, which is covered later in this chapter.
Animation reversal
Animation reversal is a useful shorthand for undoing an elements previous animation. By
invoking the reverse command, youre instructing an element to animate back to its values
prior to its last animation. A common use for reversal is animating a modal dialogue into
view, then hiding it when the user presses to close it.
An unoptimized reversal workflow consists of keeping track of the specific properties
that were last animated on each element that may later be subjected to reversal.
Unfortunately, keeping track of prior animation states in UI code quickly becomes
unwieldy. In contrast, with the reverse command, Velocity remembers everything for
you.
Mimicking the syntax of Velocitys scroll command, the reverse command is
called by passing "reverse" as Velocitys first argument:
Click here to view code image
// First animation: Animate an elements opacity toward 0
$element.velocity({ opacity: 0 });
// Second animation: Animate back toward the starting opacity value of 1
$element.velocity(reverse);
When it comes to JavaScripts animation timing control, theres more than just reversal:
JavaScript also allows you to globally slow down or speed up all JavaScript animations
currently running. Youll learn more about this powerful feature in Chapter 4, Animation
Workflow.
Physics-based motion
The utility of physics in motion design reflects the core principle of what makes for a
great user experience (UX) on your site: interfaces that flow naturally from the users
input. Put another way, interfaces that pay tribute to how objects move in the real world.
As a simple yet powerful introduction to physics-based motion Velocity offers an easing
type based on spring physics. (Well fully explore the concept of easing in the next
chapter.) With typical easing options, you pass in a string corresponding to a predefined
easing curve (for example, "ease" or "easeInOutSine"). The spring physics easing
type, in contrast, accepts a two-item array.
Click here to view code image
// Animate an elements width to 500px using a spring physics easing of 500
tensions units and 20 friction units
$element.velocity({ width: 500px }, { easing: [ 500, 20 ] });
The first item in the easing array represents the tension of the simulated spring and the
second item represents friction. A higher tension value increases the total speed and
bounciness of the animation. A lower friction value increases the vibration speed at the tail
end of the animation. By tweaking these values, you can give each animation on your page
a unique movement profile, which helps to reinforce the differentiation between their
individual behaviors.
Maintainable workflows
Designing animation is an experimental process that requires repeated tweaking of timing
and easing values to achieve a uniform feel across the page. Inevitably, just when youve
perfected your design, a client will request significant changes. In these situations,
maintainable code becomes critical.
The JavaScript-based solution to this workflow problem is wonderfully elegant, and its
covered in depth in Chapter 4, Animation Workflow. For now, heres the short
explanation: There are techniques for chaining together individual JavaScript animations
all with differing durations, easings, and so onsuch that the timing of one animation
does not affect another. This means you can change individual durations without redoing
math and you can go back and easily set animations to run either in parallel or
consecutively.
Wrapping up
When designing animations in CSS, youre inherently limited to the features that the CSS
specification provides. In JavaScript, because of the very nature of programming
languages, third-party libraries have an infinite amount of logical control over motion
design. Animation engines leverage this to provide powerful features that drastically
improve workflow and expand the possibilities of interactive motion design. Thats what
this book is all about: Designing beautiful animations as efficiently as possible.
The next chapter explains how to use this books JavaScript animation engine of choice:
Velocity.js. In mastering Velocity.js, youll understand how to leverage the features weve
just introduced, and many more.
When using jQuery and Velocity together, include jQuery before Velocity.
Thats it! Now youre ready to roll.
All the examples in this book use Velocity in combination with jQuery, and therefore
follow this syntax.
Arguments
Velocity accepts multiple arguments. Its first argument is an object that maps CSS
properties to their desired final values. The properties and their accepted value types
correspond directly to those used in CSS (if youre unfamiliar with basic CSS properties,
pick up an introductory HTML and CSS book before reading this one):
Click here to view code image
// Animate an element to a width of 500px and to an opacity of 1.
$element.velocity({ width: 500px, opacity: 1 });
Tip
In JavaScript, if youre providing a property value that contains letters
(instead of only integers), put the value in quotes.
You can pass in an object specifying animation options as a second argument:
Click here to view code image
$element.velocity({ width: 500px, opacity: 1 }, { duration: 400, easing:
swing });
This shorthand syntax is a quick way of passing in animation options when you only
need to specify the basic options (duration, easing, and complete). If you pass in an
animation option other than these three, you must switch all options to the object syntax.
Hence, if you want to specify a delay option, change the following syntax:
Click here to view code image
$element.velocity({ top: 50 }, 1000, ease-in-out);
to this syntax:
Click here to view code image
// Re-specify the animation options used above, but include a delay value of
500ms
$element.velocity({ top: 50 }, { duration: 1000, easing: ease-in-out,
delay: 500 });
Properties
There are two differences between CSS-based and JavaScript-based property animation.
First, unlike in CSS, Velocity accepts only a single numeric value per CSS property. So,
you can pass in:
Click here to view code image
$element.velocity({ padding: 10 });
or
Click here to view code image
$element.velocity({ paddingLeft: 10, paddingRight: 10 });
If you do want to animate all four padding values (top, right, bottom, and left),
Other common CSS properties that can take multiple numeric values include margin,
transform, text-shadow, and box-shadow.
Breaking up compound properties into their sub-properties for the purposes of
animation gives you increased control over easing values. In CSS, you can specify only
one property-wide easing type when animating multiple sub-properties within the parent
padding property, for example. In JavaScript, you can specify independent easing values
for each sub-propertythe advantages of this will become apparent during the discussion
of CSS transform property animation later in this chapter.
Listing out independent sub-properties can also make your animation code easier to
read and easier to maintain.
The second difference between CSS-based and JavaScript-based property animation is
that JavaScript properties drop the dashes between words and all words past the first must
be capitalized. For example, padding-left becomes paddingLeft, and
background-color becomes backgroundColor. Further note that JavaScript
property names should not be in quotes:
Click here to view code image
// Correct
$element.velocity({ paddingLeft: 10 });
// Incorrect: Uses a dash and doesnt capitalize
$element.velocity({ padding-left: 10 });
// Incorrect: Uses quotes around the JavaScript-formatted property name
$element.velocity({ paddingLeft: 10 });
Values
Velocity supports the px, em, rem, %, deg, vw, and vh units. If you dont provide a unit
type with a numeric value, an appropriate one is automatically assigned based on the CSS
property type. For most properties, px is the default unit, but a property that expects a
rotation angle, such as rotateZ for example, would be automatically assigned the deg
(degree) unit:
Click here to view code image
$element.velocity({
top: 50, // Defaults to the px unit type
left: 50%, // We manually specify the % unit type
rotateZ: 25 // Defaults to the deg unit type
});
Explicitly declaring unit types for all property values increases your codes legibility by
making the contrast between the px unit and its alternatives more obvious when quickly
Velocitys shorthand features, such as value operators, retain animation logic entirely
within the animation engine. This not only keeps the code more concise by eliminating
manual value calculation, but also improves performance by telling Velocity more about
how you plan to animate your elements. The more logic that is performed within Velocity,
the better Velocity can optimize your code for higher frame rates.
Chaining
When multiple Velocity calls are chained back-to-back on an element (or a series of
elements), they automatically queue onto one another. This means that each animation
begins once the preceding animation has completed:
Click here to view code image
$element
// Animate the width and height properties
.velocity({ width: 100px, height: 100px })
// When width and height are done animating, animate the top property
.velocity({ top: 50px });
Duration
You can specify the duration option, which dictates how long an animation call takes
to complete, in milliseconds (1/1000th of a second) or as one of three shorthand durations:
"slow" (equivalent to 600ms), "normal" (400ms), or "fast" (200ms). When
specifying a duration value in milliseconds, provide an integer value without any unit
type:
Click here to view code image
or
Click here to view code image
$element.velocity({ opacity: 1}, { duration: slow });
The advantage to using the named shorthand durations is that they express the tempo of
an animation (is it slow or is it fast?) when youre reviewing your code. If you use these
shorthands exclusively, theyll also naturally lead to more uniform motion design across
your site, since all of your animations will fall into one of three speed categories instead of
each being passed an arbitrary value.
Easing
Easings are the mathematical functions that define how fast or slow animations occur in
different parts of an animations total duration. For example, an easing type of "easein-out" indicates that the animation should gradually accelerate (ease in) during the
first part then gradually decelerate (ease out) during the final part. In contrast, an easing
type of "ease-in" produces an animation that accelerates up to a target speed during
the first part of an animation but thereafter remains at a constant speed until the animation
completes. An easing type of "ease-out" is the converse of this: the animation starts
and continues at a constant speed before it gradually decelerates during the final part of
the animation.
Much like the physics-based motion discussed in Chapter 1, Advantages of JavaScript
Animation, easings give you the power to inject personality into your animations. Take,
for example, how robotic an animation that uses the linear easing feels. (A linear easing
produces an animation that starts, runs, and ends at the same velocity.) The robotic feel is
the result of an association with linear robotic motion in the real world: Self-guided
mechanical objects typically move in straight lines and operate at constant speeds because
theres neither an aesthetic nor an organic reason for them to do otherwise.
In contrast, living thingswhether its the human body or trees blowing in the wind
never move at constant speed in the real world. Friction and other external forces cause
them to move at varying speeds.
Great motion designers pay homage to organic motion because it gives the impression
that the interface is responding fluidly to the users interaction. In mobile apps, for
example, you expect a menu to quickly accelerate away from your fingers when you swipe
it off-screen. If the menu were to instead move away from your fingers at a constant speed
like a robotic armyoud feel as if the swipe merely set off a chain of motion events
that were outside your control.
Youll learn more about the power of easing types in Chapter 3, Motion Design
Theory. For now, lets run through all of Velocitys available easing values:
jQuery UIs trigonometric easings. For a complete listing of these easing equations,
as well as interactive demonstrations of their acceleration profiles, refer to the demos
on easings.net.
CSSs Bzier curves: The Bzier curve easing allows complete control over the
structure of an easings acceleration curve. A Bzier curve is defined by specifying
the height of four equidistant points on a chart, which Velocity accepts in the format
of a four-item array of decimal values. Visit cubic-bezier.com for an interactive
guide to creating Bzier curves.
Click here to view code image
$element.velocity({ width: 100px }, [ 0.17, 0.67, 0.83, 0.67 ]);
Spring physics: This easing type mimics the bouncy behavior of a spring thats been
stretched then suddenly released. As with the classical physics equation that defines
the motion of a spring, this easing type lets you pass in a two-item array in the form
of [ tension, friction ]. A higher tension (default: 500) increases total speed and
bounciness. A lower friction (default: 20) increases ending vibration speed.
Click here to view code image
$element.velocity({ width: 100px }, [ 250, 15 ]);
Remember that you can also pass in the easing option as an explicitly defined property
in an options object argument:
Click here to view code image
$element.velocity({ width: 50 }, { easing: spring });
Do not be overwhelmed by the number of easing options available to you. Youll most
often rely on the CSS easing types and the spring easing, which suit the vast majority of
animation use cases. The most complex easing type, the Bzier curve, is most often
employed by developers who have a highly specific easing style in mind and arent afraid
to get their hands dirty.
Note
The rest of the Velocity options in this section must be explicitly passed into
an options object. Unlike those already described, these additional options
cannot be supplied to Velocity in the shorthand comma-separated syntax.
Callback Functions
These options are commonly referred to as callback functions (or callbacks)
since they are called when certain events occur in the future. Callbacks are useful
for firing events that are dependent on the visibility of elements. For example, if an
element starts at invisible then animates toward an opacity of 1, it may be
appropriate to subsequently trigger a UI event that modifies the new content once
users are able to see it.
Remember that you dont need to use callbacks to queue animations onto one
another; animations automatically fire sequentially when more than one is assigned
to a single element or set of elements. Callbacks are for the queuing of nonanimation logic.
Loop
Set the loop option to an integer to specify the number of times an animation should
alternate between the values in the calls property map and the elements values prior to
the call:
Click here to view code image
$element.velocity({ height: 10em }, { loop: 2 });
If the elements original height was 5em, its height would alternate between 5em and
10em twice.
If the begin or complete options are used with a looped call, they are triggered once
eachat the very beginning and end of the total loop sequence, respectively; they are not
retriggered for each loop alternation.
Instead of passing in an integer, you can also pass in true to trigger infinite looping:
Infinite loops ignore the complete callback since they dont naturally end. They can,
however, be manually stopped via Velocitys stop command:
$element.velocity(stop);
Non-infinite loops are useful for animation sequences that would otherwise require the
repetition of chained animation code. For example, if you were to bounce an element up
and down twice (perhaps to alert the user of a new message awaiting them), the nonoptimized code would look like this:
Click here to view code image
$element
// Assume translateY starts at 0px
.velocity({ translateY: 100px })
.velocity({ translateY: 0px })
.velocity({ translateY: 100px })
.velocity({ translateY: 0px });
The more compact and easier to maintain version of this code would look like this:
Click here to view code image
// Repeat (loop) this animation twice
$element.velocity({ translateY: 100px }, { loop: 2 });
With this optimized version, if you have a change of heart about how much the top
value should be changed by (currently "100px"), you need only change the top value in
one part of the code. If there are many such instances of repetition in your code, it quickly
becomes obvious how much looping benefits your workflow.
Infinite looping is tremendously helpful for loading indicators, which typically animate
indefinitely until data has finished loading.
First, make the loading element appear to pulsate by infinitely looping its opacity from
visible to invisible:
Click here to view code image
// Assume opacity starts at 1 (fully visible)
$element.velocity({ opacity: 0 }, { loop: true });
Later, once the data has finished loading, you can stop the animation, then hide the
element:
Click here to view code image
$element
// First stop the infinite loop
.velocity(stop)
// so you can give the element a new animation,
// in which you can animate it back to invisibility
.velocity({ opacity: 0 });
Delay
Specify the delay option in milliseconds to insert a pause before an animation begins.
The delay options purpose is to retain an animations timing logic entirely within Velocity
as opposed to relying on jQuerys $.delay() function to change when a Velocity
animation starts:
Click here to view code image
// Wait 100ms before animating opacity toward 0
$element.velocity({ opacity: 0 }, { delay: 100 });
You can set the delay option with the loop option to create a pause between loop
alternations:
Click here to view code image
// Loop four times, waiting 100ms between each loop
$element.velocity({ height: +=50px }, { loop: 4, delay: 100 });
Note
The code above effectively replaces the jQuery equivalent:
$element
.animate({ opacity:0 })
.hide();
Now, lets consider animations in the opposite direction (showing elements instead of
hiding elements): When display or visibility is set to a value other than "none"
or "hidden", the value is set before the animation begins so the element is visible
throughout the duration of the ensuing animation. In other words, youre undoing the
hiding that occurred when the element was previously removed from view.
Below, display is set to "block" before the element begins fading in:
Click here to view code image
$element.velocity({ opacity: 1 }, { display: block });
Tip
For a complete overview of Velocitys animation options, consult the
documentation at VelocityJS.org.
Reverse Command
To animate an element back to the values prior to its last Velocity call, pass in
"reverse" as Velocitys first argument. The reverse command behaves identically to
a standard Velocity call; it can take options and is queued up with other chained Velocity
calls.
Reverse defaults to the options (duration, easing, etc.) used in the elements prior
Velocity call. However, you can override these options by passing in a new options object:
Click here to view code image
// Animate back to the original values using the prior Velocity calls
options
$element.velocity(reverse);
or
Click here to view code image
// Do the same as above, but replace the prior calls duration with a value
of 2000ms
$element.velocity(reverse, { duration: 2000 });
Note
The previous calls begin and complete options are ignored by the
reverse command; reverse never re-calls callback functions.
Scrolling
To scroll the browser to the top edge of an element, pass in "scroll" as Velocitys first
argument. The scroll command behaves identically to a standard Velocity call; it can
take options and is queued up with other chained Velocity calls:
Click here to view code image
$element
.velocity(scroll, { duration: 1000, easing: spring })
.velocity({ opacity: 1 });
This scrolls the browser to the top edge of the element using a 1000ms duration and a
"spring" easing. Then, once the element has scrolled into view, it fades in fully.
To scroll toward an element inside a parent element with scrollbars, you can use the
container option, which accepts either a jQuery object or a raw element. Note that the
container element of the CSS position property must be set to either relative,
absolute, or fixedstatic wont do the trick:
Click here to view code image
// Scroll $element into view of $(#container)
$element.velocity(scroll, { container: $(#container) });
Finally, the scroll command also uniquely takes an offset option, specified in pixels,
which offsets the target scroll position:
Click here to view code image
// Scroll to a position 50px *above* the elements top edge.
$element.velocity(scroll, { duration: 1000, offset: -50px });
// Scroll to a position 250px *beyond* the elements top edge.
$element.velocity(scroll, { duration: 1000, offset: 250px });
Colors
Velocity supports color animation for these CSS properties: color,
backgroundColor, borderColor, and outlineColor. In Velocity, color
properties accept only hex strings as inputs, for example, #000000 (black) or #e2e2e2
(light gray). For more granular color control, you can animate the individual red, green,
and blue components of a color property, as well as the alpha component. Red, green, and
blue range in value from 0 to 255, and alpha (which is equivalent to opacity) ranges from
0 to 1.
Refer to the inline comments below for examples:
Transforms
The CSS transform property performs translation, scale, and rotation manipulations to
elements in both 2D and 3D space. It consists of several subcomponents, of which
Velocity supports the following:
translateX: Move an element along the x-axis.
translateY: Move an element along the y-axis.
rotateZ: Rotate an element along the z-axis (effectively clockwise or counterclockwise on a 2D surface).
rotateX: Rotate an element along the x-axis (effectively toward or away from the
user in 3D space).
rotateY: Rotate an element along the y-axis (effectively leftward or rightward in
3D space).
scaleX: Multiply the width dimension of an element.
scaleY: Multiply the height dimension of an element.
In Velocity, you animate these components as individual properties within a property
object:
$element.velocity({
translateZ: 200px,
rotateZ: 45deg
});
Velocity retains the same syntax as jQuerys $.animate() even when its used
without jQuery; the difference is that all arguments are shifted one position to the right to
make room for passing in the targeted elements in the first position. Further, the global
Velocity object is used to invoke animations instead of specific jQuery element objects.
When youre using Velocity without jQuery, youre no longer animating jQuery
element objects, but rather raw Document Object Model (DOM) elements. Raw DOM
elements can be retrieved using the following functions:
document.getElementByID(): Retrieve an element by its ID attribute.
document.getElementsByTagName(): Retrieve all elements with a
particular tag name (e.g. a, div, p).
document.getElementsByClassName(): Retrieve all elements with a
particular CSS class.
document.querySelectorAll(): This function works nearly identically to
jQuerys selector engine.
Lets further explore document.querySelectorAll() since it will probably be
your weapon of choice when selecting elements without the aid of jQuery. (Its a
performant function thats widely supported across browsers.) As with jQuerys element
selector syntax, you simply pass querySelectorAll a CSS selector (the same
selectors you use in your stylesheets for targeting elements), and it will return all matched
elements in the form of an array:
Click here to view code image
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 all divs within main
If you assign the result of one of these lookups to a variable, you can then reuse that
variable to animate the targeted element(s):
Click here to view code image
// Get all div elements
var divs = document.querySelectorAll(div);
// Animate all the divs
Velocity(divs, { opacity: 0 }, 1000);
Since youre no longer extending jQuery element objects, you may be wondering how
to chain animations back-to-back, like this:
Click here to view code image
// These chain onto one another
$element
.velocity({ opacity: 0.5 }, 1000)
.velocity({ opacity: 1 }, 1000);
To reenact this pattern without the aid of jQuery, simply call animations one after
another:
Click here to view code image
// Animations on the same element automatically chain onto one another.
Velocity(element, { opacity: 0 }, 1000);
Wrapping up
Now that youre armed with an understanding of the benefits of using JavaScript for web
animation, plus a grasp of the basics of Velocity, youre ready to explore the fascinating
theoretical foundation that underlies professional motion design.
The utility of motion design leverages user psychology. When a user presses a button,
can she be confident that the press was acknowledged by the UI? An easy way to ensure
her confidence is to animate the buttons transition to a depressed state. When a user is
waiting for content to load, can she be confident that progress is being made or is she left
with the unsettling feeling that the app has frozen? These are psychological expectations
that motion design can address by providing ongoing visual indications of the UIs state.
The complementary elegance of motion design is what elevates an app from merely
looking good to feeling good. Its the source of that ooh ahh feeling that reminds the
user how magical technology can be.
Lets master both of these aspects. Lets dive in.
Utility
How do you ensure your motion design choices are valuable additions to your site? Here
are some techniques.
Borrow conventions
Let yourself be inspired by the motion design in your favorite sites and apps. Popular
motion design conventions are worth leveraging because they already hold meaning in the
users mind. Repeated exposure to conventions leads the user to form expectations about
how certain animations should look. If you use a convention for a purpose other than
what the user has come to expect, your app will feel unintuitive.
The more you copy motion design effects from elsewhere, the more familiar your app
will feel to the user. The more familiar an app feels, the quicker the user will feel
comfortable with it and confident about it. While theres utility in novelty, the motion
design of everyday UI elements shouldnt be novel. Reserve novelty for animation
sequences that carry little meaning or are hard to misconstrue, such as a pages loading
sequence or a status indicator animation, respectively.
Preview outcomes
When an element on your page has an ambiguous purpose, give the user a preview of the
outcome of interaction. This provides reassurance that the element does what the user
thinks it does. A simple example of this would be a button that initiates a file transfer
sending out visual radio wave pulses when hovered over. This leverages a common
graphic design trope to tell the user that a data transfer action will occur.
A less ambiguous kind of previewing outcomes is to show part of the animation that
occurs when the user actually takes an action. For example, if an in-progress file transfer
indicator animation begins running when the user clicks a button, implement motion
design such that hovering over the triggering element partially runs the in-progress
animation. When the user hovers off the element, reverse the partial animation so the file
transfer indicator returns to its default state. This type of previewing technique helps the
user immediately understand the effect that her actions will trigger, which helps to
reassure her of the purpose of UI elements. The more confident the user feels, the more in
control she feels. The more in control she feels, the more pleasant her experience.
Users are tired of this. Inline status indication, in contrast, lets you show as much of the
interface as possible by blocking out only the specific subsections whose content has yet
to load. This is not only more nuanced, but also gives the user more content to fix her eyes
on while she twiddles her thumbs waiting for the page to fully load.
The takeaway here is simple: the more you give users to engage with, the longer itll
take for them to get bored.
Reflect gravitas
If the user has taken an action with irreversible consequences, reinforce that notion by
using motion design that feels equally important. For example, the animation associated
with clicking a Delete button should feel more significant than the animation associated
with hovering over a standard navigation dropdown. While the latter may entail a simple
color change, the former might consist of a sudden jump in size and a thickening of the
elements border. By divvying up motion design along a gradient of severity, youll help
the user intuitively grasp the hierarchy of the available actions. This technique, along with
the others detailed in this chapter, serves the goal of increasing user understanding and
confidence.
Reduce concurrency
To some extent, users are always trying to make sense of your UI. Consciously or
subconsciously, they ascribe meaning to every design and motion design choice you make.
So, if you present the user with extended animation sequences consisting of many
elements animating into view concurrently, youll compromise her ability to parse the
meaning of all the movements taking place.
In short, if youre using motion design to indicate something important, make sure
youre not indicating many different things at once. If you are, consider breaking
animations into steps or reducing the total animation count.
Reduce variety
Related to the best practice of reducing concurrency is the concept of limiting animation
variety: the fewer animation variations you have, the more reassured the user will feel that
shes fully abreast of what each animation in your UI connotes. For example, if you use
one type of animation for bringing big images into view, but a different type for bringing
small images into view, consider consolidating them into one. If the differentiation
between them was merely for aesthetic purposes rather than for improving usability,
youve successfully eliminated unnecessary complexity from your UI, and reinforced
behavioral consistency in the process. Consistency leads to pattern recognition and
understanding. Understanding leads to increased user confidence.
Mirror animations
A tangential aspect of limiting animation variety is consistency in your choice of
animation property and option combinations. For example, if you have a modal that
animates into view by transitioning opacity and scale, ensure that the modal
animates out of view with these two properties reverting to their original values. Dont
change properties for the two sides of the same coin. Doing so will make the user question
what prompted the differentiation, and needlessly raised questions are the hallmark of a
bad user experience.
When working with properties that affect translation (for example, translateX,
left, marginLeft in CSS), mirroring applies literally: if a modal animates into view
by sliding down from the top of the page, have it animate out of view by sliding back up
toward the top of the page. Conversely, if you were to have the modal animate out of view
by further sliding down off the page, youd be indicating to the user that the modal has
been sent somewhere new as opposed to having gone back where it came from. Typically,
you want to imply that the modal dialog has gone back where it came from now that the
user is done, say, changing account settings. If the user were instead sending an email,
then having the modal animate down off the page would be contextually appropriate
because it reinforces the idea that the email is being sent from its origin (the user) to a new
location (the recipient).
Limit durations
Designers often make the mistake of letting animations run too long, causing the user to
wait needlessly. Never let UI flourishes slow down the apparent speed of your page. If you
have a lot of content fading into view within a larger animation sequence, ensure that the
total duration across the entire sequence is short.
Similarly, if theres a part of your UIa profile image, for instancethat transitions
into or out of view on a frequent basis due to the way users interact with your page, be
extra careful not to allow protracted durations. Seeing a piece of motion design unfold is
nice the first time, but seeing it unfold a dozen times every time a user interacts with an
app becomes burdensome very quicklyespecially if the user feels that repeatedly
waiting for the animation to play out is significantly increasing the overall UI wait time.
Since its difficult to judge the appropriateness of your animation durations after seeing
them play out dozens of times during testing, a good rule of thumb is to speed up all
animations by 25 percent before you push a site live to production. This will help ensure
that they always lean toward the faster side. (See Chapter 4, Animation Workflow for
tips on how to quickly time-shift your animations.)
Limit animations
If removing an animation altogether doesnt detract from the users understanding of your
interface, consider dropping it and using an instant styling change in its place. The more
animation you have throughout your UI, the more the user will get used to seeing them.
The more she gets used to seeing them, the less attention shell pay to them, and the less
likely shell be able to differentiate between the different types of motion design and what
each signifies.
The vast majority of your motion design should be subtleminor color changes on
hovers, for exampleso the few instances of grandiose motion design that do exist should
pop to convey their intended message.
Elegance
The line between frivolous and consequential motion design is an easy one to discern:
does a particular piece of motion design satisfy one of the best practices discussed in the
Utility section of this chapter? If not, remove it. Its frivolous, and its jeopardizing the
usability of your UI.
Dont be frivolous
To hone your judgment about what is frivolous, download the most popular apps, play
with each extensively, and judge whether they feature animation to a greater or lesser
extent than your app does. Play close to attention to what each animation conveys, and
why it conveys it. If you feel that these apps use animation to a much lesser extent than
yours does, consider toning back the motion design in your UI.
Theres one exception to this dont-be-frivolous mantraread on!
If you have a really cool idea for animating your content into view, then do it here. But
be sure to respect all the other rules in this chapter, especially limiting durations.
Consider personality
If you were designing a corporate site, you wouldnt use a bounce effect to transition
elements into view. Bounciness is playfulnot a quality that corporate sites often want to
convey. And if you were designing an educational or government app, you wouldnt use
easings that result in movement that starts very quickly before finishing very slowly
(thereby conveying a whizzing-by-your-face futuristic slickness)these would probably
be too glossy and stylized for the content at hand.
Always be considerate of the personality expressed by your animation decisions. As a
designer, its hard to judge the tone of your own work, so its a good idea to get third-party
feedback early and often. Ask test users whether a UI feels suitably professional, friendly,
and sleek, and tweak your motion design according to your preference for each of those
three traits.
Go beyond opacity
The most common means of transitioning an element into or out of view is to animate its
opacity from 0 to 1, and vice versa. This can be rather boring. Opacity is just the base
property that has to be animated when displaying or hiding contentits not the only
property. You can spice up your property choices by scaling an element down into view,
sliding it up out of view, or changing its background color. As you add more properties to
an animation, consider leveraging multistep effects, which youll learn about in the next
technique.
other. Just like layering up clothing to create pleasant color and texture combinations, you
should layer animations to create pleasant motion design combinations.
For advice on the technical implementation of multistep effects, read Chapter 4,
Animation Workflow.
Stagger animations
When multiple sibling elementssay, a series of images in a galleryare animating into
view at the same time, consider adding a tiny successive delay between them. (That is,
after the first image loads, a delay occurs before the second image loads, and so on.) To
delay the animation of sibling elements in this way is called staggering, and its purpose is
similar to that of breaking an animation into steps: it adds visual layering by preventing all
your elements from animating perfectly in sync, which can look plain and inelegant
compared to staggered loading. Why? Because animating a series of elements in sync
lacks any semblance of granularity or gradience. Consider this: Birds dont fly side by side
in a straight line. What makes their aerial movements so graceful is their successive
formation and timing. Its their juxtaposition, and the motion of their juxtaposition, that
makes them so elegant to the human eye.
Use graphics
Make use of scalable vector graphics (SVG) to animate individual graphic components of
a larger element that the user can interact with (learn more in Chapter 6, Scalable Vector
Graphics Primer). A common example of this is the trio of horizontal lines that constitute
a hamburger menu icon, or the dots that form a circle in a loading indicator. In both of
these examples, arbitrary shapes are grouped together to form a common UI component.
Before SVG animation was possible on the web, the common approach to animating a
graphic like either of the two described was to embed the full graphic as a PNG image and
then animate the entire shape by transitioning its opacity in CSS. By leveraging SVG,
however, you can animate these unique elements on an individual shape-by-shape basis
and subject them to many types of property animations.
Graphic animation is a surefire way to add nuance to key portions of your UI. This
nuance is partially a result of the fact that web-based animation primarily deals with solid,
rectangular shapes. (Sometimes they have rounded corners, but the shapes nonetheless
remain solid and whole.) Animating the individual shapes of an element instead lets you
delight the user with motion design that she might not have realized was even possible.
Beyond novelty, you can also uniquely leverage SVG animation to transform shapes
into brand-new ones. Pairing this with the techniques for previewing outcomes and
flowing from the triggering element, you can use graphic transformations to indicate UI
behavior and provide feedback to the user. For example, if hovering over the dots in a
loading indicator causes those dots to rearrange themselves into an X shape, that would
indicate to the user that clicking the status indicator graphic would cancel the loading of
content.
Experiment Repeatedly
Finding the right duration, stagger, easing, and property combinations for each
animation is not a skill that designers are born with. Its a skill that every great
designer has had to learn. So, remember: your first attempt at a combination of
animation properties might look good, but its probably not the best case. There are
only two ways to find the best case: experiment by systematically changing each
factor in the motion design equation until you stumble onto something sublime, or
borrow ideas from other peoples work. Once youve found a combination you like
even if its one youve already borrowed elsewhere pixel-for-pixelexperiment
further. Consider cutting the duration in half, switching to a completely different
easing type, or swapping out a property.
Designers are often averse to extended experimentation becauseeven though
there are a million ways to animate a button into vieweach way effectively
fulfills the goal at hand: making the button visible. Consequently, once you stumble
onto a combination of properties that look good, youre likely to stick with it
because it looks good and it works. But dont forget that goodness isnt a
respectable design goalgreatness is. Greatness entails stepping outside your
comfort zone, and not necessarily relying on what you already know works.
Wrapping up
Utility and elegance are your goals. At minimum, all animation code must fulfill one or
the other.
When implemented properly, animation code should provide concrete value to your UX
and not adversely impact the websites performance. No matter how sleek your motion
design is, if the interface is laggy as a result of its implementation, the overall user
experience will not be elegant. Youll learn more about the importance of performance in
the Chapter 7, Animation Performance.
You then specify the value that each particular CSS property should change toward, per
the transition rule. In the case of the hover example, the divs text color will change
to blue when the user hovers over it:
div:hover {
color: blue;
}
Thats it. In only a few lines of code, CSS handles interaction state for you: when the
user hovers away from the div, CSS will animate the change from blue back to the
preexisting text color over a duration of 200ms.
What Does Good Code Look Like?
Good code is expressive, meaning that its purpose is easy to grasp. This is crucial
not only for coworkers attempting to integrate your foreign code, but also for
yourself in the future, once youve forgotten your original approach. Good code is
also terse, meaning that it accomplishes what it needs to in as few lines as possible;
every line serves an important purpose, and it cant be rewritten away. Lastly, good
code is also maintainable, meaning that its individual parts can be updated without
fear of compromising the integrity of the whole.
In contrast, coding this same effect in jQuery would entail the following:
Click here to view code image
$div
// Register a mouseover event on this div, which calls an animation
function
.on(mouseover, function() {
$(this).animate({ color: blue }, 200);
})
// When the user hovers off the element, animate the text color back to
black
.on(mouseout, function() {
// Note: We have to remember what the original property value was
(black)
This might not look so bad, but the code isnt taking advantage of the fact that
JavaScript provides an infinite amount of logical control. It goes out of its way to do
something that CSS is designed for: triggering logicless animations that occur on the same
element that the user is interacting with. Above, youre doing in JavaScript what you
could have done in fewer, more expressive, and more maintainable lines of CSS. Even
worse, youre not getting any additional feature benefits by implementing this
functionality in JavaScript.
In short, if you can easily use CSS transitions to animate an element thats never being
animated by JavaScript (meaning theres no potential for conflict), then you should code
that animation in CSS. For all other UI animation tasksmulti-element and multistep
sequences, interactive drag animations, and much moreJavaScript animation is the
superior solution.
Lets explore the fantastic workflow techniques JavaScript provides.
Standard approach
In jQuery animation, its common to animate CSS classes onto elements using the UI addon plugin (jQueryUI.com). When the module is loaded, jQuerys addClass() and
removeClass() functions are upgraded with animation support. For example, lets 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:
Click here to view code image
// 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:
Click here to view code image
$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 pages 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 its 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, lets look at the optimized approach.
Its just as beneficialand often the best methodology for JavaScript-centric animation
workflowsto 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:
Click here to view code image
// 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:
Click here to view code image
// Pass our named properties object into Velocity
$element.velocity(fadeIn, 1000);
To recap, in your style.js, youve defined a JavaScript object thats populated with the
CSS properties you want to animate. This is the same object thats then passed into
Velocity as a first argument. Youre not doing anything fancy herejust saving objects to
named variables, then passing those variables into Velocity instead of the raw objects
themselves.
Note
This technique works equally well with jQuerys animate() function.
The benefit of switching from CSS to JavaScript to segregate logic is that your style.js
file is uniquely capable of defining animation optionsnot 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 animations properties; the second defines its options.
In this case, your style.js file would look like this:
Click here to view code image
var fadeIn = {
// p is for properties
p: {
opacity: 1,
top: 50px
},
// o is for options
o: {
duration: 1000,
easing: linear
}
};
Pretty and clean, right? Someone skimming it would understand its purpose, and would
know where to look to modify its propertiesthe style.js file. Further, the purpose of this
animation is immediately evident: because youve 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 theres 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:
Click here to view code image
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:
Click here to view code image
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 dont 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.
The specific UI pack feature discussed in this section is called sequence running. It will
forever change your animation workflow. It is the solution to messily nested animation
code.
Standard approach
Without the UI pack, the standard approach to consecutively animating separate elements
is as follows:
Click here to view code image
// Animate element1 followed by element2 followed by element3
$element1.velocity({ translateX: 100, opacity: 1 }, 1000, function() {
$element2.velocity({ translateX: 200, opacity: 1 }, 1000, function() {
$element3.velocity({ translateX: 300, opacity: 1 }, 1000);
});
});
Dont let this simple example fool you: in real-world production code, animation
sequences include many more properties, many more options, and many more levels of
nesting than are demonstrated here. Code like this most commonly appears in loading
sequences (when a page or a subsection first loads in) that consist of multiple elements
animating into place.
Note that the code shown above is different from chaining multiple animations onto the
same element, which is hassle-free and doesnt require nesting:
Click here to view code image
// Chain multiple animations onto the same element
$element1
So whats wrong with first code sample (the one with different elements)? Here are the
main issues:
The code bloats horizontally very quickly with each level of nesting, making it
increasingly difficult to modify the code within your IDE.
You cant easily rearrange the order of calls in the overall sequence (doing so
requires very delicate copying and pasting).
You cant easily indicate that certain calls should run parallel to one another. Lets
say that halfway through the overall sequence you want two images to slide into
view from different origin points. When coding this in, it wouldnt be obvious how
to nest animations that occur after this parallel mini-sequence such that the overall
sequence doesnt become even more difficult to maintain than it already is.
Optimized approach
Before you learn about the beautiful solution to this ugly problem, its important to
understand two simple features of Velocity. First, know that Velocity accepts multiple
argument syntaxes: the most common, when Velocity is invoked on a jQuery element
object (like all the code examples shown so far), consists of a properties object followed
by an options object:
Click here to view code image
// The argument syntax used thus far
$element.velocity({ opacity: 1, top: 50px }, { duration: 1000, easing:
linear });
An alternative syntax pairs with Velocitys utility function, which is the fancy name
given to animating elements using the base Velocity object instead of chaining off of a
jQuery element object. Heres what animating off the base Velocity object looks like:
Click here to view code image
// Velocity registers itself on jQuerys $ object, which you leverage here
$.Velocity({ e: $element, p: { opacity: 1, scale: 1 }, o: { duration: 1000,
easing: linear } });
As shown above, this alternative syntax consists of passing Velocity a single object that
contains member objects that map to each of the standard Velocity arguments (elements,
properties, and options). For the sake of brevity, the member object names are truncated to
the first letter of their associated objects (e for elements, p for properties, and o for
options).
Further, note that youre now passing the target element in as an argument to Velocity
since youre no longer invoking Velocity directly on the element. The net effect is exactly
the same as the syntax you used earlier.
As you can see, the new syntax isnt much bulkier, but its equallyif not more
expressive. Armed with this new syntax, youre ready to learn how the UI packs
sequence-running feature works: you simply create an array of Velocity calls, with each
call defined using the single-object syntax just demonstrated. You then pass the entire
array into a special Velocity function that fires the sequences calls successively. When
one Velocity call is completed, the next runseven if the individual calls are targeting
different elements:
Click here to view code image
// Create the array of Velocity calls
var loadingSequence = [
{ e: $element1, p: { translateX: 100, opacity: 1 }, o: { duration: 1000
} },
{ e: $element2, p: { translateX: 200, opacity: 1 }, o: { duration: 1000
} },
{ e: $element3, p: { translateX: 300, opacity: 1 }, o: { duration: 1000
} }
];
// Pass the array into $.Velocity.RunSequence to kick off the sequence
$.Velocity.RunSequence(loadingSequence);
Expressiveness and maintainability arent the only benefits to sequence running: you
also gain the ability to run individual calls in parallel using a special sequenceQueue
option which, when set to false, forces the associated call to run parallel to the call that
came before it. This lets you have multiple elements animate into view simultaneously,
giving a single Velocity sequence the power to intricately control timing that would
normally have to be orchestrated through messy callback nesting. Refer to the inlined
comments below for details:
Click here to view code image
$.Velocity.RunSequence([
{ elements: $element1, properties: { translateX: 100 }, options: {
duration: 1000 } },
// The following call will start at the same time as the first call since
it uses the `sequenceQueue: false` option
{ elements: $element2, properties: { translateX: 200 }, options: {
duration: 1000, sequenceQueue: false },
// As normal, the call below will run once the second call has completed
{ elements: $element3, properties: { translateX: 300 }, options: {
duration: 1000 }
];
Standard approach
Instead of simply animating the opacity of an element toward 1, you might
simultaneously animate its scale property so that the element appears to both fade in and
grow into place. Once the element is fully in view, you might choose to animate its border
thickness to 1rem as a finishing touch. If this animation were to happen multiple times
across a page, and on many different elements, it would make sense to avoid code
repetition by turning it into a standalone function. Otherwise, youd have to repeat this
non-expressive code throughout your script.js:
Click here to view code image
$element
.velocity({ opacity: 1, scale: 1 }, { duration: 500, easing: ease-in-out
})
.velocity({ borderWidth: 1rem }, { delay: 200, easing: spring,
duration: 400 });
Unlike the sequencing technique discussed in the previous section, the code above
consists of multiple animations that all occur on the same element. Chained animations on
a singular element constitute an effect. If you were to improve this effect by implementing
the first technique in this chapter (turning CSS classes into JavaScript objects), youd have
to go out of your way to uniquely name each argument object for each stage in the overall
animation. Not only is it possible that these objects wouldnt be used by other portions of
the animation code due to the uniqueness of this particular sequence, but youd have to
deal with appending integers to each animation calls respective objects to delineate them
from one another. This could get messy, and could neutralize the organizational benefit
and brevity of turning CSS classes into JavaScript objects.
Another problem with effects such as the one above is that the code isnt very selfdescriptiveits purpose isnt immediately clear. Why are there two animation calls
instead of one? What is the reasoning behind the choice of properties and options for each
of these individual calls? The answers to these questions are irrelevant to the code that
triggers the animation, and should consequently be tucked away.
Optimized approach
Velocitys UI pack lets you register effects that you can subsequently reuse across a site.
Once an effect is registered, you can call it by passing its name into Velocity as its first
parameter:
Click here to view code image
// Assume we registered our effect under the name growIn
$element.velocity(growIn);
Thats a lot more expressive, isnt it? You quickly understand the codes purpose: An
element will grow into view. The code remains terse and maintainable.
Whats more, a registered effect behaves identically to a standard Velocity call; you can
pass in an options object as normal and chain other Velocity calls onto it:
Click here to view code image
$element
// Scroll the element into view
.velocity(scroll)
// Then trigger the growIn effect on it, with the following settings
.velocity(growIn, { duration: 1000, delay: 200 })
If the UI pack is loaded onto your page, an effect such as this is registered using the
following syntax:
Click here to view code image
$.Velocity.RegisterEffect(name, {
// Default duration value if one isnt passed into the call
defaultDuration: duration,
// The following Velocity calls occur one after another, with each taking
up
a predefined percentage of the effects total duration
calls: [
[ propertiesObject, durationPercentage, optionsObject ] ,
[ propertiesObject, durationPercentage, optionsObject ]
],
reset: resetPropertiesObject
});
the element is hidden so that subsequent effects neednt worry about the properties
beyond opacity they must reset on the element for their calls to properly take
effect. In other words, you can leverage the reset properties map to make effects
self-contained, such that they leave no clean up duties on the target elements.
In addition to the reset object, another powerful workflow bonus of the UI packs effect
registration is automatic display property toggling. When an element begins animating
into view, you want to ensure its display value is set to a value other than none so the
element is visible throughout the course of its animation. (Remember, display: none
removes an element from the pages flow.) Conversely, when fading an element out, you
often want to ensure its display value is switched to "none" once its opacity hits 0.
This way, you remove all traces of the element when youre done using it.
Using jQuery, display toggling is accomplished by chaining the show() and hide()
helper functions onto animations (oftentimes messily buried within nested callbacks).
With Velocitys UI pack, however, this logic is taken care of automatically when you
suffix your effect names with In and Out as appropriate.
Lets register two UI pack effectsone for the In direction and one for the Out
directionand call the element shadowIn since it consists of fading and scaling an
element into view, then expanding its boxShadow property outward:
Click here to view code image
$.Velocity
.RegisterEffect(shadowIn, {
defaultDuration: 1000,
calls: [
[ { opacity: 1, scale: 1 }, 0.4 ] ,
[ { boxShadowBlur: 50 }, 0.6 ]
]
})
.RegisterEffect(shadowOut, {
defaultDuration: 800,
calls: [
// We reverse the order to mirror the In direction
[ { boxShadowBlur: 50 }, 0.2 ],
[ { opacity: 0, scale: 0 }, 0.8 ]
]
});
If your effects name ends with Out, Velocity will automatically set the elements
display property to none once the animation is complete. Conversely, if your effects
name ends with In, Velocity will automatically set the elements display property to
the default value associated with the elements tag type (for example, "inline" for
anchors, "block" for div and p). If your effects name does not contain one of these
special suffixes, the UI pack will not perform automatic display setting.
Registering effects not only improves your code, but also makes it highly portable
between projects and among fellow developers. When youve designed an effect you love,
now its painless to share the effects registration code with others so they can use it too.
Pretty neat!
Design techniques
The techniques discussed so far in this chapter will improve your workflow during the
coding phase of motion design. The techniques covered in this section focus on the design
phase, where youre still experimenting to find the perfect animation that fits your UI.
This phase requires a lot of creativity and a lot of repetition, and is accordingly ripe for
workflow improvements.
Timing multipliers
The first design technique is to use a global timing multiplier. This consists of sprinkling
in a multiplier constant against all of your animations delay and duration values.
Start by defining your global timing multiplier (arbitrarily designated as M for
multiplier):
var M = 1;
Then, bake the multiplier into the duration and delay option values within each
animation call:
Click here to view code image
$element1.animate({ opacity: 1 }, { duration: 1000 * M });
$element2.velocity({ opacity: 1 }, { delay: 250 * M });
Note
if you use SASS or LESS, which provide support for variable usage within
stylesheets, this technique applies equally to CSS animations!
Embedding a multiplier constant will help you quickly modify the M constant in one
location (presumably at the top of your style.js) in order to quickly speed up or slow down
all of the animations across your page. Benefits of such timing control include:
Slowing down animations to perfect the timing of individual animation calls within a
complex animation sequence. When youre constantly refreshing your page in order
to tweak a multi-element animation sequence to perfection, seeing the sequence in
slow motion makes it significantly easier to assess how individual elements interact
with one another.
Speeding up animations when youre performing repetitive UI testing. When youre
testing a site for purposes other than animation, evaluating the end state of UI
animations (how elements wind up) is more important than testing the animations
motion. In these situations, it saves time and reduces headaches to speed up all the
animations across your page so youre not repeatedly waiting for your animations to
play out on each page refresh.
Velocity has a handy implementation of this functionality called mock, which functions
as a behind-the-scenes global multiplier so you dont have to sprinkle in the M constant by
hand. Like the example shown above, mock multiplies both the duration and the
delay values. To turn mock on, temporarily set $.Velocity.mock to the multiplier
Velocitys mock feature also accepts a Boolean value: setting mock to true sets all
durations and delays to 0ms, which forces all animations to complete within a single
browser timing tick, which occurs every few milliseconds. This is a powerful shortcut for
quickly turning off all animations when theyre getting in the way of your UI development
and testing.
Once youve designed all your element animations exactly the way you want them, you
can export your work into one-for-one Velocity code, which you can place immediately
into an IDE for use in production. (The resulting code is also fully compatible with
jQuery.)
Ultimately, VMD saves countless hours of development time by preventing constant
IDE and browser tab switching and repeated UI state retriggering. Further, it streamlines
the designer-to-developer workflow by allowing the two teams to work alongside one
another in real time: with VMD, designers can implement motion design without having
to familiarize themselves with a sites JavaScript or CSS. They can simply hand off the
exported Velocity code to the developers to integrate into the codebase at their discretion.
VMD is a highly visual toolvisit VelocityJS.org/#vmd to see the walkthrough video.
Wrapping up
As you implement animation workflow techniques, youll notice the intimidating black
box of motion design beginning to unfold. The beautifully intricate loading sequences
found on cutting-edge sites like Stripe.com and Webflow.com will start to make sense to
you. Youll gain confidence in your ability to code animation sequences, and this
newfound skill will reduce friction in your development routine, making it not only easier
but also significantly more fun to accomplish your motion design goals.
<span class=blast>Hello</span>
<span class=blast>World</span>
</div>
As you can see, Blast separated the target divs text into text parts that are individually
wrapped in span elements. If you were to instead use the character delimiter, the result
would have been:
Click here to view code image
<div class=blast-root>
<span class=blast>H</span>
<span class=blast>e</span>
<span class=blast>l</span>
<span class=blast>l</span>
<span class=blast>o</span>
<span class=blast> </span>
<span class=blast>W</span>
<span class=blast>o</span>
<span class=blast>r</span>
<span class=blast>l</span>
<span class=blast>d</span>
</div>
You can now animate these span elements independently. Before you dive into textual
animation, however, youre going to learn more about how Blast works so you can take
full advantage of its powerful features.
This div element is composed of two children: a text node (Hello) and a span element
node. The span element node contains a child of its own: another text node (World).
When Blast is called, it traverses the entirety of the target elements descendant element
chain to find text nodes. With each text node, Blast executes the RegEx query associated
with the specified delimiter type (character, word, or sentence) to subdivide the
node into new elements, each with its own text node part. Since Blast doesnt actually
subdivide element nodesonly text nodesyou can safely apply it to the entire page
without worrying about breaking elements event handlers and other expected behaviors.
This versatility is crucial when using Blast on user-generated content that is often dirtied
with HTML. (Say, for example, you want to separate the words in a message posted to
your sites comments section so you can highlight important passages. With Blast, you can
safely do so without concern for breaking the users embedded links.)
In addition to its robustness, Blast provides a high level of accuracy. It doesnt dumbly
split words at spaces, nor does it split sentences at periods within words. It leverages UTF8 character sets for Latin alphabet languages, meaning that you can accurately apply it to
French, German, Spanish, English, Italian, and Portuguese content.
Suppose you used Blasts sentence delimiter on the following paragraph. (Bold and
italic are used below to indicate the consecutive text matches that Blast detects.) Blast
correctly identified six sentences in the paragraph:
Will the sentence delimiter recognize this full sentence containing Spanish
punctuation? Yes! Mais, oui ! Nested quotes dont break the sentence
delimiter! Further, periods inside words (e.g. Blast.js), in formal titles (e.g. Mrs. Bluth,
Dr. Fnke), and in e.g. and i.e. do not falsely match as sentence-final punctuation.
Darn. Thats pretty impressive.
Notice how punctuation is associated with its proper sentence, and how errant periods
dont falsely demarcate sentence matches.
With these foundations covered, its time to run through how to use Blast.
Installation
Blast is installed on a page like any other JavaScript plugin: embed the appropriate script
link before your pages </body> tag:
Click here to view code image
<html>
<head>My Page</head>
<body>
My content.
<script src=jquery.js></script>
<script src=velocity.js></script>
<script src=blast.js></script>
</body>
</html>
Note
Blast requires jQuery (or Zepto, a jQuery alternative), and therefore must be
required after jQuery. It doesnt matter whether Blast is loaded before or after
Velocity.
Once Blast is loaded, use it by calling .blast() on a jQuery element object. It
accepts an options object as its sole argument:
Click here to view code image
$element.blast({ option1: value1, option2: value2 });
Option: Delimiter
Blasts most important option is delimiter, which accepts "character", "word",
or "sentence". To separate the text within $element using the "sentence"
delimiter, your code would look like this:
Click here to view code image
$element.blast({ delimiter: sentence });
Note that Blast returns the generated text wrapper elements to the jQuery selector chain
so you can manipulate them, like this:
Click here to view code image
$element.blast({ delimiter: sentence })
.css(opacity, 0.5);
The .css() call is applied to the individual text elements, not the parent $element
that you called Blast on.
Option: customClass
Blast provides two options to make text manipulation easier: customClass and
generateValueClass. customClass behaves exactly as you would expect: supply
a custom class (as a string value) to be assigned to the text node wrapper elements.
Suppose you had the following div and Blast call:
Click here to view code image
<div>
Hi Mom
</div>
$(div).blast({ delimiter: word , customClass: myClass });
The div would turn into the following (note how Blast automatically assigns every text
part the "blast" class by default):
Click here to view code image
<div>
<span class=blast myClass>Hi</span>
<span class=blast myClass>Mom</span>
</div>
Option: generateValueClass
generateValueClass takes a Boolean value (true or false) indicating whether a
unique class, in the form of .blast-[delimiter]-[textValue], should be
assigned to the generated text elements.
Note
This option is applicable only to the character and word delimiters.
The [delimiter] placeholder represents the delimiter type used in the call, and the
[textValue] placeholder represents the text contained within an individual element.
Consider the following example:
Click here to view code image
<div>
Hi Mom
</div>
$(div).blast({ delimiter: word , generateValueClass: true });
When Blast is called with the letter delimiter, the element would turn into this
instead:
Click here to view code image
<div class=blast-root>
<span class=blast blast-letter-H>H</span>
<span class=blast blast-letter-i>i</span>
and so on
</div>
Thanks to this feature, you can painlessly target text matches via either CSS or
JavaScript without having to use messy custom code to individually check the text
contents of each element.
Option: Tag
This option lets you specify the type of element that wraps text parts. The default value is
span, but you can pass in any element type (for example, a, div, p). Consider this
example:
Click here to view code image
<div>
Hi Mom
</div>
// Use the div element as the wrapper tag
$(div).blast({ delimiter: word , tag: div });
This feature is useful to ensure that the resulting text elements mimic the structure of
the surrounding HTML. Perhaps nearby sibling elements are all of the div type, in which
case the above example may be appropriate.
You might also want to take advantage of the unique properties offered by different tag
types. strong, for example, automatically bolds text, whereas div forces each text
match to begin on a new line thanks to divs default display value of "block".
Command: Reverse
You can undo Blast on an element by passing false as the sole parameter into a Blast
call. Hence, if your Blasted element looked like this:
<div class=blast-root>
<div class=blast>Hi</div>
<div class=blast>Mom</div>
</div>
You might be wondering how this works: when Blast is reversed, it simply destroys the
generated wrapper elements, then inserts raw text where the wrapper elements were
previously. Note that this will break event handlers assigned to the new elements
generated by Blast, but it wont break event handlers associated with the HTML that
existed prior to Blast being initially called.
Reversing Blast in this way is a crucial component of textual animation since the modus
operandi when animating elements on a webpage is to leave things as they were before
you touched them. If, for example, youve Blasted apart a sentence in order to animate its
words into view one at a time, you would subsequently reverse Blast upon completion of
the animation. Consequently, JavaScript code that later interacts with the text wont have
unexpected child elements that it has to parse out. In short, its good practice to avoid
leaving your HTML unnecessarily bloated so that further programmatic interaction with
your elements doesnt become increasingly convoluted.
Note
To learn more about Blast, including its unique search capabilities and its
compatibility with screen-reading software, visit its documentation at
Julian.com/research/blast.
Now that youve separated your text elements, its time to animate them.
Because the div starts out as visible, Blasting the divs text results in child text
elements that are visible as well. Since your goal is to animate the generated text elements
into view starting from a state of invisibility, you have to make the generated text elements
invisible immediately after you call Blast:
Click here to view code image
$(div)
.html(This is our new message.)
.blast({ delimiter: word })
.css(opacity, 0);
.velocity({ opacity: 1 });
This replaces the divs existing text with a new message. Then it Blasts the div using the
word delimiter. Since a call to Blast returns the generated text wrapper elements to the
jQuery selector chain, you can easily extend the code to set the opacity of each text
element to 0. This primes the elements for the subsequent Velocity call, which consists of
a simple opacity animation.
You may have noticed that the above code results in all text parts animating into view
simultaneously. This, of course, defeats the purpose of using Blast in the first place: if you
wanted all of the divs content to animate into view simultaneously, you could have
simply animated the div itself. The goal here is actually to achieve a successive
animation sequence that consists of one text element animating after another.
Staggering
This is where Velocitys UI pack comes into play. (Review Chapter 4, Animation
Workflow, if you need a primer on the UI pack.) To impose a successive delay between
animation start times within an element set, use Velocity UI packs stagger option,
which expects a duration specified in milliseconds. Applying it to the previous code
example, you get:
Click here to view code image
$(div)
.html(This is our new message.)
.blast({ delimiter: word })
.css(opacity, 0)
.velocity(transition.fadeIn, { stagger: 50 });
The code above produces a successive delay of 50ms between the elements animation
start times. Importantly, note the Velocity calls previous { opacity: 1 } argument
for "transition.fadeIn", which is a premade fade effect included with Velocitys
UI pack. (Refer to Chapter 4, Animation Workflow, if you need a refresher.) Since the
stagger option works with UI pack effects, this example shows the effect that mirrors
animating opacity to a value only of 1.
As discussed in Chapter 3, Motion Design Theory, be careful to keep stagger times to
a low duration so that users arent waiting needlessly while text fades into view. Keep in
mind that the longer an elements word count, the greater the overall time an animation
sequence will take to complete. Text element staggering is one of the easiest ways to slip
into the bad practice of slowing down your interface.
Both examples above target the third element on the page that has the .blast class
applied. (Note that jQuerys eq function is 0-based whereas CSS nth-child is 1based, hence the different integer values being passed into the examples.) Lets continue
with a jQuery implementation to work toward a complete example:
Click here to view code image
<div>
Current status: paused
</div>
// Blast the div using the word delimiter
$(div).blast({ delimiter: word })
// Select the third word in the sentence (the span containing the
paused text)
.eq(2)
// Fade the third element out of view then replace its inner text
with a new message
.velocity({ opacity: 0 }, function() { $(this).text(running); })
// Fade the replaced text into view
.velocity({ opacity: 1 });
This Blasts a sentence, selects its third word (paused), fades the word out of view,
replaces the faded word with a new word (running), then fades the new word into view.
The net effect is that the status-indicating keyword within a sentence gracefully fades into
a new word to alert the user of a change. This is a tremendously elegant effect that consists
of only a few lines of simple code. If you were to perform this effect many times over a
larger block of text, you could achieve an effect in which one message appears to
sporadically change into another.
"inline"the default display value for span and anchor elements in particular. The
workaround is to set Blasts generated text elements to a display value of "inlineblock", which keeps "inline" elements behaving as they normally do while giving
them the added functionality of "block" elements (such as div and p), in which
position-related properties, including 3D transforms, can be styled. Taking this display
tweak into account, the inward text transition example would now look like this:
Click here to view code image
$(div)
.html(message)
.blast({ delimiter: word })
.css({ opacity: 0, display: inline-block })
.velocity(transition.perspectiveDownIn, { stagger: 50 });
This sets the Blasted text parts display values to "inline-block" in the same
call to jQuerys css() function that sets the elements opacity to a starting value of 0.
Textual flourishes
The final topic in this discussion of textual animation is the concept of flourishes, ambient
animations that produce ongoing effects for aesthetic purposes. One example might be a
string of text that flickers like a dying light bulb. Another might be having all the words in
a sentence continuously animate to different shades of blue.
Both of these are bad ideas.
These effects distract users and ultimately amuse only youthe developer who enjoys
toying with motion design. Never include animation just for the sake of animation; if a
part of your page is meaninglessly drawing the users attention away from the parts that
have utility, go back to the drawing board.
The rare exception to this is status indicatorstext such as Loadingthat keep the
user abreast of what the interface is doing. These are appropriate targets for textual
flourishes because the flourishes tell the user that the interface is still processing data (as
opposed to having frozen). In this way, flourishes act as an engaging visual heartbeat.
So if textual flourishes are generally considered bad practice, why is this section even
included in the book? Because flourishes that arent animated are often a great idea!
Consider this a non-animation bonus provided by Blast: you can stylize the text elements
generated by Blast to produce colorful collages and other unique typographic designs. For
example, you could break apart a websites slogan text (Delivering happiness right to
your door!) word by word to reduce the opacity of each successive word, thereby
creating a subtle gradient effect that spans the entire sentence. Heres what that code
would look like:
Click here to view code image
<div>
Hi Mom
</div>
// Blast the div then iterate through the generated text elements
$(div).blast({ delimiter: character }).each(function(i, element) {
// Successively reduce the opacity of each element with an arbitrary
formula
Instead of iterating opacity values, you could also iterate RGB values to create colorbased gradients. For example, if you increased the blue component of text whose color
initially starts as gray, youd produce elements that are increasingly rich in blue as you go
from first to last:
Click here to view code image
// Blast the div then iterate through the generated text elements
$(div).blast({ delimiter: character }).each(function(i, element) {
// Successively increase the blue color component of each element with an
arbitrary formula
var adjustedBlue = i*20;
element.style.opacity = rgb(0, 0, + adjustedBlue + );
});
Wrapping up
This is just the beginning of the possibilities created by granular text control. Other
techniques include fine-tuning the coordinates of every letter in a word to produce a
collage effect, or placing words around the circumference of a circle to mimic the
typographic design you might find on a drink coaster.
While these techniques may be well-suited for bold homepage centerpieces, they may
not be appropriate for critical parts of your UI that are subject to repeated user interaction.
Why? Because stylized text is harder to read at a glance than unstylized text. But if you
consider the balance between form and function, youll be fine.
SVG markup
SVG elements are defined within a parent <svg> container. Specifying the width and
height dimensions of container element defines the canvas that your SVG graphics render
upon:
Click here to view code image
<svg version=1.1 width=500 height=500
xmlns=http://www.w3.org/2000/svg>
<circle cx=100 cy=100 r=30 />
<rect id=rect x=100 y=100 width=200 height=200 />
</svg>
Within <svg>, you can insert SVG shape elements of varying sorts. The above
example has a circle element followed by a rect (rectangle) element. As with normal
HTML elements, SVG elements accept height and width attributes, which are used
here for demonstration purposes, but (as with HTML) its considered best practice to
specify SVG styling properties within a CSS stylesheet. Also as with HTML, stylesheet
classes target SVG elements via their id, class, or tag types.
Where the SVG and HTML specifications fundamentally differ is in their range of
accepted HTML attributes and CSS properties. SVG elements accept only a few of the
standard CSS properties. Further, SVGs accept a special set of attributes, called
presentational attributes, which include fill, x, and y. (fill specifies which color to
fill a shape with, whereas x and y define the position of the elements top-left corner.)
These attributes define how an element is visually rendered on its canvas. Lets run
through a few of them, using rect as a sample SVG element:
Click here to view code image
<rect id=rect x=100 y=100 width=200 height=200 />
Here, the width and height attributes work as youd expect. The unique x and y
attributes define the rectangles coordinates within the canvas. These values simply
position the rectangle relative to an x = 0, y = 0 origin point. Unlike HTML, SVG
positioning is not defined with top, right, bottom, left, float, or margin CSS
properties; SVG positioning logic is fully dictated by explicitly defined coordinates. In
other words, an SVG elements positioning doesnt affect the position of its sibling
elements; instead of pushing each other around the page, SVG siblings simply overlap one
another.
Now lets take a look at the circle element. Its rendering is specified via coordinates
that designate its center point (cx and cy) along with a radius value (r) that designates its
length:
Click here to view code image
<circle cx=100 cy=100 r=30 />
Pretty simple, right? SVG elements use the same markup structure as HTML elements,
so all the code samples in this chapter should feel familiar.
Note that there are many other types of SVG elements, including ellipse, line, and text.
See the end of this chapter for further details.
SVG styling
SVG elements accept a variety of special styling properties that are not available to HTML
elements. SVGs fill property, for example, is similar to background-color in
CSS, stroke is similar to border-color, and stroke-width is similar to
border-width. Take a look at this example:
Click here to view code image
<svg version=1.1 width=500 height=500
xmlns=http://www.w3.org/2000/svg>
<circle cx=100 cy=100 r=30 style=fill: blue />
<rect id=rect x=100 y=100 width=200 height=200 style=fill:
green; stroke: red; stroke-width: 5px />
</svg>
Above, the circle element is filled with solid blue, and the rect element is filled
with solid green. Additionally, the rectangle has a red border with a thickness of 5px.
There are many other SVG-specific styling properties. For now, its simply important
for you to know that they exist so youll pay extra attention when trying to animate CSS
properties on SVG elements.
Note
Refer to the Wrapping up section of this chapter for information on where
to find a full listing of SVG styling properties.
SVG animation
SVG elements might never be the backbone of your UI, but theyre certainly appropriate
for spicing up the parts of your page that youd normally fill with static images. Uses for
SVGs include:
Buttons with intricate animation sequences that are triggered when users hover and
click.
Unique loading status graphics that replace the all-too-common rotating indicator
GIF.
Company logos whose individual parts animate together upon page load.
This last use case is explored in more detail later in this chapter.
Passing in properties
With Velocity, SVG properties are animated in the same way that standard CSS properties
are. Pass the appropriate properties and their desired end values into Velocitys properties
object:
In contrast, note that the code below would not work since the following CSS properties
are not supported by SVG elements:
Click here to view code image
// Incorrect: These properties dont apply to SVG elements
$svgElement.velocity({ borderSize: 5px, borderColor: #000000 });
Presentational attributes
The presentational attributes explored earlier in this chapter are also animated as expected:
Click here to view code image
// Animate the x and y coordinates of a rectangle
$(rect).velocity({ x: 100, y: 100 });
// Animate the cx and cy coordinates of a circle
$(circle).velocity({ cx: 100, cy: 100 });
// Animate the dimensions of a rectangle
$(rect).velocity({ width: 200, height: 200 });
// Animate the radius of a circle
$(circ).velocity({ r: 100 });
All the Velocity features that youre currently usinganimation reversal, UI pack
effects, sequence triggering, and so onalso work as expected with SVG elements.
Note
Although transforms are known to be particularly performant due to hardware
acceleration (read more on this in Chapter 7, Animation Performance), both
approaches to SVG animation are equally fast since SVG graphics are
hardware-accelerated by default.
This creates two overlapping circles with identical radii. Next, youd animate the circles
outward from their origins so that they overlap only slightly when theyre done animating:
Click here to view code image
// Move one circle toward the left
$(#circleLeft).velocity({ cx: -=15px }, { easing: spring });
// Move one circle toward the right
$(#circleRight).velocity({ cx: +=15px }, { easing: spring });
Here, the left circle is animated 15 pixels leftward (using the "-=" operator to instruct
Velocity to decrement the circles current value) and the right circle is animated 15 pixels
rightward. The spring easing provides added flair by making the circles bounce away
from one another with propulsive force.
Since SVG elements can listen for mouse-based events (clicks, hovers, and so on), you
could improve upon this demo by turning it into an example of SVG element interaction.
With the aid of jQuery and Velocity, one such implementation could look like this:
Click here to view code image
$(svg).on(mouseover mouseout, function() {
$(#circleLeft, #circleRight).velocity(reverse);
});
This triggers a reversal of the circles page-load animation when the user hovers on or
off the SVG element. The single line of code accomplishes this by leveraging Velocitys
reverse animation command. For more on working with reverse, refer to Chapter 2,
Animating with Velocity.js. In effect, when the user first hovers, the page-load
animation is reversed. When the user then hovers off, the reversal is itself reversed,
bringing the logo back to its original form.
While this code example is undoubtedly anticlimactic, this is once again a good thing
because it reflects the similarities between animating SVG and HTML elements. Where
SVGs do start to become uniquely complex is when you define arbitrary shapes that go
beyond the basics of squares, rectangles, circles, and so on. After all, SVG elements can
define any shape you can dream up in a photo editor, so they have to be tremendously
expressive. And they are. But mastering SVG design is beyond the scope of this book. See
the Wrapping up section of this chapter to learn where to go next to continue learning.
Wrapping up
If youre intrigued by what youve read so far and want to learn more about working with
SVGs, check out these great resources:
For a full overview of working with SVG elements, refer to Joni Trythalls fantastic
and free SVG Pocket Guide (https://github.com/jonitrythall/svgpocketguide).
For a directory of SVG element types and their properties, consult Mozilla
Developer Network (https://developer.mozilla.org/en-US/docs/Web/SVG).
For a listing of all the SVG attributes and styling properties that Velocity can
animate, refer to VelocityJS.org/#svg.
Note
Ericsson has reported that the global smartphone subscriber count will rise
from 1.9 billion to 5.9 billion in the next five yearsfueled almost
exclusively by the developing world.
If your gut reaction is, Its not my problemmy app is just for the tech-savvy middleclass in the developed world, rest assured that your evil web developer twin is sitting two
thousand miles away cackling at the thought of getting to a nascent market before you do
by actually putting in the effort necessary to deliver great experiences on low-powered
devices. (Theres actually an enormous conglomerate dedicated to thissearch Google for
Rocket Internet.)
Theres another nasty reality to sidelining performance concerns: we systematically
make the mistake of testing our sites on devices operating under ideal loads. In reality, of
course, users have multiple apps and browser tabs running concurrently. Their devices are
working overtime to process a dozen tasks at any given time. Accordingly, the
performance baseline established for your app probably doesnt reflect its performance in
the real world. Yikes!
But, fear not, keen developer. Its time to explore the performance techniques at your
disposal and level up your animation game.
Problem
Consider how webpage manipulation consists of setting and getting: you can set (update)
or get (query) an elements CSS properties. Likewise, you can insert new elements onto a
page (a set) or you can query for a set of existing elements (a get). Gets and sets are
the core browser processes that incur performance overhead (another is graphical
rendering). Think of it this way: after setting new properties on an element, the browser
has to calculate the resulting impacts of your changes. For example, changing the width of
one element can trigger a chain reaction in which the width of the elements parent,
siblings, and children elements must also change depending on their respective CSS
properties.
The UI performance reduction that occurs from alternating sets with gets is called
layout thrashing. While browsers are highly optimized for page-layout recalculations, the
extent of their optimizations is greatly diminished by layout thrashing. Performing a series
of gets at once, for example, can easily be optimized by the browser into a single,
streamlined operation because the browser can cache the pages state after the first get,
then reference that state for each subsequent get. However, repeatedly performing one
get followed by one set forces the browser to do a lot of heavy lifting since its cache is
continuously invalidated by the changes made by set.
This performance impact is exacerbated when layout thrashing occurs within an
animation loop. Consider how an animation loop aims to achieve 60 frames per second,
the threshold at which the human eye perceives buttery-smooth motion. What this means
is that every tick in an animation loop must complete within 16.7ms (1 second/60 ticks ~=
16.67ms). Layout thrashing is a very easy way to cause each tick to exceed this limit. The
end result, of course, is that your animation will stutter (or jank, in web animation
parlance).
While some animation engines, such as Velocity.js, contain optimizations to reduce the
occurrence of layout thrashing inside their own animation loops, be careful to avoid layout
thrashing in your own loops, such as the code inside a setInterval() or a selfinvoking setTimeout().
Solution
Avoiding layout thrashing consists of simply batching together DOM sets and DOM
gets. The following code causes layout thrashing:
Click here to view code image
// Bad practice
var currentTop = $(element).css(top); // Get
$(element).style.top = currentTop + 1; // Set
var currentLeft = $(element).css(left); // Get
If you rewrite the code so that all queries and updates are aligned, the browser can batch
the respective actions and reduce the extent to which this code causes layout trashing:
Click here to view code image
var currentTop = $(element).css(top); // Get
var currentLeft = $(element).css(left); // Get
$(element).css(top, currentTop + 1); // Set
$(element).css(left, currentLeft + 1); // Set
implementations, the browser is instructed to search through the DOM tree to find the
desired element. This is an operation that, when repeated in bulk, impacts page
performance.
This performance concern is exacerbated when uncached elements are used in code
snippets that are repeated, such as the code contained by a loop. Consider the following
example:
Click here to view code image
$elements.each(function(i, element) {
$(body).append(element);
});
You can see how $("body") is a JEO instantiation thats repeated for every iteration
of the $.each() loop: In addition to appending the loops current element to the DOM
(which has its own performance implications), youre now also repeatedly forcing a DOM
query. Seemingly harmless one-line operations like these add up very quickly.
The solution here is to cache the resultsor, save the returned JEOs into variablesto
avoid a repeated DOM operation every time you want to call a jQuery function on an
element. Hence, the code goes from looking like this:
Click here to view code image
// Bad practice: We havent cached our JEO
$(#element).css(opacity, 1);
// some intermediary code
// We instantiate the JEO again
$(#element).css(opacity, 0);
Now you can reuse $element throughout your code without ever incurring a repeated
DOM lookup on its behalf.
Force-feeding
Traditionally, animation engines query the DOM at the start of an animation to determine
the initial value of each CSS property being animated. Velocity offers a workaround to this
page-querying event through a feature called force-feeding. Its an alternative technique
for avoiding layout thrashing. With force-feeding, you explicitly define your animations
start values so that these upfront gets are eliminated.
Force-fed start values are passed in as the second item in an array that takes the place of
a propertys value in an animation properties map. The first item in the array is the
standard end value that youre animating toward.
Consider the following two animation examples, both of which are triggered upon page
load:
Click here to view code image
// Animate translateX to 500px from a start value of 0
$element.velocity({ translateX: [ 500, 0 ] });
// Animate opacity to 0 from a start value of 1
$element.velocity({ opacity: [ 0, 1 ]);
In the first example, youre passing translateX a force-fed start value of 0 since you
know that the element has yet to be translated (since the page has just loaded). Youre
force-feeding in what you know (or want) the original property value to be. Further, in the
second example, the elements current opacity is 1 because thats the default value for
opacity and you havent yet modified the element in any way. In short, with forcefeeding, you can reduce the browsers workload in situations where you have an
understanding of how elements are already styled.
Note
Force-feed animation properties only when theyre first used in an animation
chain, not when they occur subsequently in the chain, since Velocity already
does internal caching there:
Click here to view code image
$element
// Optionally forcefeed here
.velocity({ translateX:[ 500, 0 ] })
// Do not forcefeed here;500 is internally cached
.velocity({ translateX:1000 });
Problem
Youre not done with gets and sets just yet! A common page set is the insertion of
new DOM elements at run-time. While there are many uses for adding new elements to a
page, perhaps the most popular is infinite scrolling, which consists of elements
continuously animating into view at the bottom of a page while the user scrolls downward.
As you learned in the previous section, browsers have to compute the composition of all
affected elements whenever a new element is added. This is a relatively slow process.
Hence, when DOM insertion is performed many times per second, the page is hit with a
significant performance impact. Fortunately, when processing multiple elements, browsers
can optimize page set performance if all elements are inserted at the same time.
Unfortunately, we as developers often unintentionally forgo this optimization by
separating our DOM insertions. Consider the following example of unoptimized DOM
insertion code:
Click here to view code image
// Bad practice
var $body = $(body);
var $newElements = [ <div>Div 1</div>, <div>Div 2</div>, <div>Div
3</div> ];
$newElements.each(function(i, element) {
$(element).appendTo($body);
// Other arbitrary code
});
This iterates through a set of element strings that are instantiated into jQuery element
objects (without a performance drawback since youre not querying the DOM for each
JEO). Each element is then inserted into the page using jQuerys appendTo().
Heres the problem: even if additional code exists after the appendTo() statement,
the browser wont compress these DOM sets into a single insertion operation because it
cant be certain that asynchronous code operating outside the loop wont alter the DOMs
state between insertions. For example, imagine if you queried the DOM to find out how
many elements exist on the page after each insertion:
Click here to view code image
// Bad practice
$newElements.each(function(i, element) {
$(element).appendTo($body);
// Output how many children the body element has
console.log($body.children().size());
});
The browser couldnt possibly optimize the DOM insertions into a single operation
because the code explicitly asks the browser to tell us the accurate number of elements
that exist before the next loop begins. For the browser to return the correct count each
time, it cant have batched all insertions upfront.
In conclusion, when you perform DOM element insertion inside a loop, each insertion
happens independently of any others, resulting in a notable performance sacrifice.
Solution
Instead of individually inserting new elements into the DOM, construct the full DOM
element set in memory, then insert it via a single call to appendTo(). The optimized
version of the code shown in the section above now looks like this:
Click here to view code image
// Optimized
var $body = $(body);
var $newElements = [ <div>Div 1</div>, <div>Div 2</div>, <div>Div
3</div> ];
var html = ;
$newElements.each(function(i, element) {
html += element;
});
$(html).appendTo($body);
This concatenates the string representation of each HTML element onto a master string
that is then turned into a JEO and appended into the DOM in a single shot. In this way, the
browser is given explicit instruction to insert everything at once, and it optimizes for
performance accordingly.
Simple, right? As youll see in the remainder of this chapter, performance best practices
are usually as easy as this. You simply have to train your eye to know when to use them.
Problem
When an elements dimensions are animated, the changes often affect the positioning of
nearby elements. For example, if an element between two sibling elements shrinks in
width, the siblings absolute positions will dynamically change so they remain next to the
animating element. Another example might be animating a child element nested inside a
parent element that doesnt have explicitly defined width and height properties.
Accordingly, when the child is being animated, the parent will also resize itself so that it
continues to fully wrap itself around the child. In effect, the child element is no longer the
only element being animatedthe parents dimensions are also being animated, and thats
even more work for the browser to perform upon each tick in an animation loop!
There are many CSS properties whose modification can result in dimensional and
positional adjustments to neighboring elements, including top, right, bottom, and
left; all margin and padding properties; border thickness; and the width and
height dimensions.
As a performance-minded developer, you need to appreciate the impact that animating
these properties can have on your page. Always ask yourself how each property youre
attempting to animate affects nearby elements. If theres a way to rewrite your code such
that you can isolate elements changes from one another, then consider doing so. In fact,
there is an easy way to do just thison to the solution!
Solution
The simple solution to avoid affecting neighboring elements is to animate the CSS
transform properties (translateX, translateY, scaleX, scaleY, rotateZ,
rotateX, and rotateY) whenever possible. The transform properties are unique in that
they elevate targeted elements to isolated layers that are rendered separately from the rest
of the page (with a performance boost courtesy of your GPU), so that neighboring
elements arent affected. For example, when animating an elements translateX to a
value of 500px", the element will move 500px rightward while superimposing itself on
top of whatever elements exist along its animation path. If there are no elements along its
path (that is, if there are no nearby elements for it to affect), then using translateX will
have the same net effect on the look of your page as if you had animated using the much
slower left property.
Hence, whenever possible, an animation that once looked like this:
Click here to view code image
// Move the element 500px from the left
$element.velocity({ left: 500px });
Note
Sometimes you actually intend to use left or top so that neighboring
elements positions are changed. In all other cases, get into the habit of using
the transform properties. The performance impact is significant.
Consider Opacity Over Color
opacity is another CSS property that receives a GPU rendering boost since it
doesnt affect the positioning of elements. So, if there are elements on your page for
which youre currently animating, say, color when the user hovers over them,
consider animating opacity instead. If the net effect looks almost as good as the
color animation, then consider sticking with ityouve just boosted the UIs
performance without compromising its look.
As a performance-minded developer, youre no longer allowed to arbitrarily select
animation properties. You must now consider the impact of each of your property choices.
Note
Refer to CSSTriggers.com for a breakdown of how CSS properties affect
browser performance.
Problem
When a page first loads, the browser processes HTML, CSS, JavaScript, and images as
quickly as possible. It should come as no surprise that animations occurring during this
time tend to be laggytheyre fighting for the browsers limited resources. So, despite the
fact that a pages loading sequence is often a great time to flaunt all your motion design
skills, its best to restrain yourself if you want to avoid giving users the first impression
that your site is laggy.
A similar concurrency bottleneck arises when many animations occur at once on a page
regardless of where they take place in the pages lifecycle. In these situations, browsers
can choke under the stress of processing many styling changes at once, and stuttering can
occur.
Fortunately, there are some clever techniques for reducing concurrent animation load.
Solution
There are two approaches for addressing the concurrency issue: staggering and breaking
up animations into sequences.
Stagger
One way to reduce concurrent animation load is to make use of Velocitys UI packs
stagger feature, which delays the start times of successive animations in a set of
elements by a specified duration. For example, to animate every element in a set toward an
opacity value of 1 with successive 300ms delays between start times, your code might
look like this:
Click here to view code image
$elements.velocity({ opacity: 1 }, { stagger: 300 });
The elements are no longer animating in perfect synchronization; instead, at the very
start of the entire animation sequence, only the first element is animating. Later, at the
very end of the entire sequence, only the last element is animating. Youre effectively
spreading out the animation sequences total workload so that the browser is always
performing less work at one time than it would have had it been animating every element
simultaneously. Whats more, implementing staggering into your motion design is often a
good aesthetic choice. (Chapter 3, Motion Design Theory, further explores the merits of
staggering.)
Multi-animation sequences
Theres one more clever way to reduce concurrent load: break up property animations into
multi-animation sequences. Take, for example, the case of animating an elements opacity
value. This is typically a relatively low-stress operation. But, if you were to
simultaneously animate the elements width and box-shadow properties, youd be
giving the browser appreciably more work to perform: more pixels will be affected, and
more computation would be required.
Hence, an animation that looks like this:
Click here to view code image
$images.velocity({ opacity: 1, boxShadowBlur: 50px });
The browser has less concurrent work to do since these individual property animations
occur one after another. Note that the creative tradeoff being made here is that weve opted
to prolong the total animation sequence duration, which may or may not be desirable for
your particular use case.
Since an optimization such as this entails changing the intention of your motion design,
this is not a technique that should always be employed. Consider it a last resort. If you
need to squeeze additional performance out of low-powered devices, then this technique
may be suitable. Otherwise, dont pre-optimize the code on your site using techniques like
this, or youll end up with unnecessarily bloated and inexpressive code.
Problem
Browsers scroll and resize events are two event types that are triggered at very high
rates: when a user resizes or scrolls the browser window, the browser fires the callback
functions associated with these events many times per second. Hence, if youve registered
callbacks that interact with the DOMor worse, contain layout thrashingthey can cause
tremendously high browser load during times of scrolling and resizing. Consider the
following code:
Click here to view code image
// Perform an action when the browser window is scrolled
$(window).scroll(function() {
// Anything in here is fired multiple times per second while the user
scrolls
});
// Perform an action when the browser window is resized
$(window).resize(function() {
// Anything in here is fired multiple times per second while the user
resizes
});
Recognize that the functions above arent simply called once when their respective
events start; instead, they are called throughout the duration of the users respective
interaction with the page.
Solution
The solution to this problem is to debounce event handlers. Debouncing is the process of
defining an interval during which an event handler callback will be called only once. For
example, say you defined a debounce interval of 250ms and the user scrolled the page for
a total duration of 1000ms. The debounced event handler code would accordingly fire
only four times (1000ms/250ms).
The code for a debounce implementation is beyond the scope of this book. Fortunately,
many libraries exist exclusively to solve this problem. Visit davidwalsh.name/javascriptdebounce-function for one example. Further, the tremendously popular Underscore.js
(UnderscoreJS.org), a JavaScript library akin to jQuery that provides helper functions for
making coding easier, includes a debounce function that you can easily reuse across your
event handlers.
Note
As of this books writing, the latest version of Chrome automatically
debounces scroll events.
Problem
Videos and images are multimedia element types that browsers have to work extra hard to
render. Whereas the dimensional properties of non-multimedia HTML elements can be
computed with ease, multimedia elements contain thousands of pixel-by-pixel data points
that are computationally expensive for browsers to resize, reposition, and recomposite.
Animating these elements will always be less less than optimal versus animating standard
HTML elements such as div, p, and table.
Further, given that scrolling a page is nearly equivalent to animating a page (think of
scrolling as animating the pages top property), multimedia elements can also drastically
reduce scrolling performance on CPU-constrained mobile devices.
Solution
Unfortunately, theres no way to refactor multimedia content into faster element types,
other than turning simple, shape-based images into SVG elements wherever possible.
Accordingly, the only available performance optimization is reducing the total number of
multimedia elements that are displayed on the page at once and animated at once. Note
that the words at once stress a reality of browser rendering: browsers only render whats
visible. The portions of your page (including the portions that contain additional images)
that arent visible do not get rendered, and do not impose additional stress on browser
processes.
So, there are two best practices to follow. First, if youre ever on the fence about adding
an additional image to your page, opt to not include it. The fewer images there are to
render, the better UI performance will be. (Not to mention the positive impact fewer
images will have on your pages network load time.)
Second, if your UI is loading many images into view at once (say, eight or more,
depending on your devices hardware capabilities), consider not animating the images at
all, and instead crudely toggling the visibility of each image from invisible to visible. To
help counteract how inelegant this can look, consider staggering visibility toggling so that
the images load into view one after another instead of simultaneously. This will help guide
the users eye across the loading sequence, and will generally deliver more refined motion
design.
Note
Refer to Chapter 3, Motion Design Theory, to learn more about animation
design best practices.
Sneaky images
Youre not done yet. Theres more to this section than meets the eye, as we havent fully
explored the ways in which images can materialize on a page. The obvious culprit is the
img element, but there are two other ways that images can sneak onto your pages.
CSS gradients
These are actually a type of image. Instead of being pre-produced by a photo editor, they
are produced at run-time according to CSS styling definitions, for example, using a
linear-gradient() as the background-image value on an element. The
solution here is to opt for solid-color backgrounds instead of gradients whenever possible.
Browsers can easily optimize the rendering of solid chunks of color, but, as with images,
they have to work overtime to render gradients, which differ in color from pixel to pixel.
Shadow properties
The evil twin siblings of gradients are the box-shadow and text-shadow CSS
properties. These are rendered similarly to gradients, but instead of stylizing
background-color, they effectively stylize border-color. Whats worse, they
have opacity falloffs that require browsers to perform extra compositing work because the
semitransparent portions of the gradients must be rendered against the elements
underneath the animating element. The solution here is similar to the previous one: if your
UI looks almost as good when you remove these CSS properties from your stylesheet, pat
yourself on the back and never look back. Your websites performance will thank you.
These recommendations are simply that: recommendations. They are not performance
best practices since they sacrifice your design intentions for increased performance.
Considered them only as last resorts when your sites performance is poor and youve
exhausted all other options.
Problem
Internet Explorer 8a slow, outdated browseris dying in popularity. But Internet
Explorer 9, its successor, is still widely used outside of the Americas. Further, older
Android smartphones running Android 2.3.x and below, which are slow relative to the
latest-generation Android and iOS devices, also remain tremendously popular. Out of
every ten users to your site, expect up to three of them to fall into one of these two groups
(depending on the type of users your app attracts). Accordingly, if your site is rich in
animation and other UI interactions, assume it will perform especially poorly for up to a
third of your users.
Solution
There are two approaches to addressing the performance issue raised by weaker devices:
either broadly reduce the occurrence of animations across your entire site, or reduce them
exclusively for the weaker devices. The former is a ultimately a product decision, but the
latter is a simple technical decision that is easily implemented if youre using the global
animation multiplier technique (or Velocitys equivalent mock feature) explained in the
Chapter 4, Animation Workflow. The global multiplier technique lets you dynamically
alter the timing of animations across your entire site by setting a single variable. The trick
thenwhenever a weak browser is detectedis to set the multiplier to 0 (or set
$.Velocity.mock to true) so that all of a pages animations complete within a
single animation tick (less than 16ms):
Click here to view code image
// Cause all animations to complete immediately
$.Velocity.mock = true;
The result of this technique is that weaker devices experience UI animations that
degrade so that instant style changes replace your animated transition. The benefits are
significant: your UI will perform noticeably more smoothly without resource-intensive
animations occurring on your page. While this technique is undoubtedly destructive (it
compromises your motion design intentions), an improvement in usability is always worth
a reduction in elegance. After all, users visit your app to accomplish specific goals, not to
admire how clever your UI work is. Never let animations get in the way of user intentions.
If youre still irked by the notion of stripping animations from your UI, keep in mind
that users on weaker devices are accustomed to websites behaving slowly for them. So, if
your site bucks the trend in a constructive way, theyll be especially delighted by it and
will be more likely to continue using it.
on test devices will be offset by the increased recurring revenue youll generate from
happier users engaging more frequently with your buttery-smooth app.
If you wind up with a handful of reference devices, also consider purchasing Device
Lab, a versatile stand that props up all of your mobile devices on a single surface so you
can easily eyeball the screens during testing. As a bonus, the device includes a nifty app
that lets you control all the browsers across your devices at once so you dont have to
manually refresh each browser tab.
Note
Visit Vanamco.com to purchase and download Device Lab.
Wrapping up
Performance affects everything. From how many devices can run your app, to the quality
of the user experience, to the perception of your apps technical competency, performance
is a major tenet of professional web design. Its not a nice-to-have, its a fundamental
building block. Dont relegate performance as a simple optimization to be made in
hindsight.
Behavior
The demo consists of 250 circles floating in, out, and around the screen. Periodically,
youll zoom in, then back out to the position where the virtual camera started. The first
image presented momentarily shows a zoomed-in view.
Note
Before you continue reading, head on over to VelocityJS.org/demo.book.html
to see a live preview of the demo. (You can right-click anywhere on the page
then choose View Source to see the demos code.)
The circle elements are simply normal divs with box-shadow and borderradius set in CSS. Theres no WebGL or Canvas animation going on herejust pure
HTML element manipulation. (Given the volume of elements that are being animated at
once, its quite impressive that this demo is capable of running so smoothly in the DOM!)
Lets break down the animation: It consists of div elements translating along the X, Y,
and Z axes. The Z-axis dictates the depth of each elements animation, whereas X and Y
provide the general flowing, 2D movement seen across the screen. Concurrent to the
elements individual movements is a larger perspective shift that occurs on the element
containing all these divs. This perspective shift occurs every 3 seconds, and it creates a
periodic zooming effect that makes the viewer feel as if hes briefly traveling through the
circles 3D space.
The second graphic depicts the 3D scene in its zoomed-out view. Contrast this with the
zoomed-in view shown in the first image.
Code structure
Lets take a look at the code that powers this demo. It is structured as follows:
5. Animation setup: The specification of parameters used for constraining animation
movement.
6. Circle creation: The generation of the div elements to be animated.
7. Container animation: The code responsible for animating the circles parent
element.
8. Circle animation: The code responsible for animating the circle elements
themselves.
Try to familiarize yourself with the broader strokes of the demos implementation so
you can keep its full context in mind as you explore each individual code block in the
upcoming sections:
Click here to view code image
/************************
Animation setup
************************/
/* Randomly generate an integer between two numbers. */
function r (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
/* Query the windows dimensions. */
var screenWidth = window.screen.availWidth,
screenHeight = window.screen.availHeight;
/* Define the z-axis animation range. */
var translateZMin = -725,
translateZMax = 600;
/**********************
Circle creation
**********************/
var circleCount = 250,
circlesHtml = ,
$circles = ;
for (var i = 0; i < circleCount; i++) {
circlesHtml += <div class=circle></div>;
}
$circle = $(circlesHtml);
/******************************
Container animation
******************************/
$container
.css(perspective-origin, screenWidth/2 + px + screenHeight/2 + px)
.velocity(
{
perspective: [ 215, 50 ],
opacity: [ 0.90, 0.55 ]
}, {
duration: 800,
loop: 1,
delay: 3000
});
/***************************
Circle animation
***************************/
$circles
.appendTo($container)
.velocity({
opacity: [
function() { return Math.random() },
function() { return Math.random() + 0.1 }
],
translateX: [
function() { return += + r(-screenWidth/2.5, screenWidth/2.5) },
function() { return r(0, screenWidth) }
],
translateY: [
function() { return += + r(-screenHeight/2.75, screenHeight/2.75)
},
function() { return r(0, screenHeight) }
],
translateZ: [
function() { return += + r(translateZMin, translateZMax) },
function() { return r(translateZMin, translateZMax) }
]
}, { duration: 6000 })
.velocity(reverse, { easing: easeOutQuad })
.velocity({ opacity: 0 }, 2000);
The first section, Animation setup, begins by defining a function r (abbreviated from
"random") that lets you artificially constrain randomly generated integer values. This
function takes min and max parameters, then outputs a random number between the min
to max range (using some basic algebra). Youll use this later when randomizing the
animating elements CSS transform values within ranges that are predefined in the
next two code blocks.
The next section queries the window object to retrieve the monitors dimensions. By
later referencing these values, you can ensure that the circles dont animate too far offscreen (and consequently out of view).
Animation setup concludes by defining the min and max values for the elements Zaxis movement. These values control how small (far away) or large (nearby) you want the
circles to animate from their initial size. Specifically, it dictates that the circles can go as
far as 725 pixels along the Z-axis away from the virtual camera (away from the screen),
and as close as 600 pixels toward the camera. In this case, theres no constraint of going
off-screen, but the circle could become too distant to see or so close that it takes up the
entire monitor. Basically, its a creative decision.
The demos second section, Circle creation, generates the primary div elements to be
animated. Here, it first defines the desired number of circles as circleCount. Then, it
defines a circlesHtml string to contain the circles collated HTML.
Next, it iterates up to the circleCount number to generate the circles HTML.
Notice that it uses the performance best practice of batching DOM additions, as detailed in
Chapter 7, Animation Performance. It collates the markup for each div element onto a
master circlesHtml string thats later inserted into the DOM in a single action. (If you
were to insert the div elements into the DOM one at a time, the negative performance
impact would be significant: UI interaction in the browser would be frozen until the
relatively slow element insertion process completed.)
Finally, it wraps the circle elements in a jQuery element object so they can be easily
manipulated as a group in the upcoming Circle animation section.
3D CSS primer
Lets begin the first of the two animation sections of the codebase by focusing on the
element that contains the circle elements. Before diving into the code, however, heres a
primer on how 3D animation works in the browser:
In order for 3D transforms to work (for example, translateZ, rotateX,
rotateY), the CSS specification requires that the perspective CSS property be set
on the elements parent. In this case, thats what the $container element is for.
The greater the value that perspective is set to, the less distance Z-axis translations
(via CSSs translateZ) appear to move relative to their origin. In other words, if you
want more exaggerated depth in your 3D animations, set the parent elements
perspective property to something low, such as 50px, which is in fact the value that
the container element is set to in the demos CSS. In contrast, a higher perspective
value, such as 250px, would result in less visible movement from the origin point for
every pixel that the elements translateZ property is incremented by.
A separate and complementary CSS property is prospective-origin, which
defines the angle at which the virtual camera is positioned. The virtual camera is the
peephole through which the viewer sees 3D animation unfold in the browser. This
sections code block uses jQuerys $.css() function to set a perspective-origin
value on the container element that results in the camera being positioned at the center of
the page, creating a perpendicular view of the 3D animation. This perpendicular view
results in the appearance of circles flying directly toward and away from the viewer.
Specifically, this code section sets perspective-origin to the point on the page
thats at half the browsers height and half its widththe center point of the page. This
leverages the window dimensions queried in the Animation setup section.
With that context out of the way, lets explore this sections code.
Properties
This sections code, reproduced below for easy reference, creates the demos zooming in
and out effect:
Click here to view code image
$container
.css(perspective-origin, screenWidth/2 + px + screenHeight/2 + px)
.velocity(
{
perspective: [ 215, 50 ],
opacity: [ 0.90, 0.55 ]
}, {
duration: 800,
loop: 1,
delay: 3250
});
While the prospective-origin property is set once on the container element and
thereafter left alone, the prospective property is being animated by Velocity. This is
necessary because the intended effect of the demo is to keep the vantage point into the
scene stationary (perpendicular), but to exaggerate then de-exaggerate the distance of the
elements from the virtual camera, which is where the perspective propertys
animation comes in.
Specifically, this section uses Velocity to animate the perspective CSS property to
a final value of 215px from a starting value of 50px.
By passing in an array as an animation propertys value, youre forcefully specifying
the final value to animate the property toward (215px, in the case above) as well as the
initial value to animate from (50px, in the case above). While you certainly could have
passed the property a single integer value as is typically expected by Velocity, the forcefeeding syntax provides increased control over the propertys complete animation path.
You might be wondering, isnt force-feeding unnecessary since Velocity knows how to
retrieve a CSS propertys starting value on its own? While that is Velocitys standard
behavior when an integer is passed in as a value instead of an array, this isnt always a
desirable behavior due to the performance drawbacks inherent to querying the DOM for a
propertys starting value. What the force-feeding syntax allows you to do is explicitly pass
in a starting value so that Velocity can avoid querying the DOM for a property whose
starting value you already know. In other words, the 50px starting value used in the
perspective code above is the same value you initially set the container elements
perspective property to in the CSS stylesheet. Youre simply repeating the value here.
Notice that this same force-feeding technique is used on the elements opacity property
as well: its animated to a final value of 0.90 from a starting value of 0.55 since thats what
the property was set to in the CSS.
As discussed thoroughly in Chapter 7, Animation Performance, DOM queries are
indeed the Achilles heel of performant animation: the browser performs resourceintensive calculations to determine the visual state of an element. While its not important
to the demos performance that you include this performance optimization, since the
associated Velocity animation isnt being triggered repeatedly inside a loop, its included
nonetheless to contrast force-feedings secondary use, which youll learn about later in this
chapter.
The net effect of animating the perspective and opacity is that all of the
containers circle elements appear to zoom in closer to the virtual camera while animating
to an increased brightness (opacity goes from 0.55 to 0.90). The opacity boost mimics
the way that light behaves in the real world: the closer the viewer is to the objects, the
brighter they appear!
Options
The final section of Container animation code includes the options being passed into
Velocity: duration, which is self explanatory; delay, which inserts a time-out at the
start of the animation, and loop, which loops an animation back and forth between the
values defined in the properties map and the elements values prior to the animation
occurring. Specifically, by setting loop to 2, youre telling Velocity to animate to the
values in properties map, back to where they were before, then to repeat this full loop
iteration once more after a 3000ms delay.
Note
When delay is set alongside loop, the delay occurs between each of the
loops alternations. Using delay creates a pleasant pause so that the zoom-in
and zoom-out effect doesnt zigzag back and forth abruptly.
Value functions
Unlike the static animation property values used in the previous section (for example, [
215, 50 ]), this section uses functions for property values: each property is force-fed
an array of start and end values that are dynamically produced by functions. Lets briefly
explore these value functions, which are a unique feature of Velocity.
Note
Read more about value functions at VelocityJS.org/#valueFunctions.
Value functions let you pass in functions as animation property values. These functions
trigger at run-time, and are called individually for each element animated in a set. In the
demo, the set in question is the circle divs contained within the $circles jQuery
element object. Consequently, each circle element property will be assigned its own
randomized value once the animation begins. The only other way to achieve
differentiation between animation properties in a set of elements is to animate the
elements separately by looping through them, which gets messy and performs badly. This
is the benefit of value functionsyou keep dynamic animation code terse and
maintainable.
Notice that, to produce the randomized values, this section of code leverages our r
helper function that was defined in Animation setup. (As a reminder, the r function
returns a randomized integer value constrained by its min and max arguments.) Youll
learn more about this function momentarily.
Opacity animation
The opacity property animates from and toward randomized values. In the case of the
starting value, youre giving the randomized value a slight boost to ensure that the
elements are never too close to being invisibleafter all, you want the viewer to see what
youre animating! The animation of opacity results in a smattering of circles all over
the page that have varying opacities from the very first frame. Differentiated opacities
create a nice gradient effect that adds visual richness to the demo.
This code takes advantage of force-feeding for a purpose other than performance
optimization: value functions are being force-fed to dynamically generate start values for
the elements that have yet to be inserted into the DOM, which means that youre
successfully avoiding writing an entirely new code block just to set the initial CSS states
of the circle elements. Youre dynamically providing unique starting positions in the same
line of code responsible for animating those positions. As discussed thoroughly in Chapter
4, Animation Workflow, you should strive for this level of expressiveness in all of your
animation code.
Translation animation
For easy reference, heres this sections code once again:
Click here to view code image
/***************************
Circle animation
***************************/
$circles
.appendTo($container)
.velocity({
opacity: [
function() { return Math.random() },
function() { return Math.random() + 0.1 }
],
translateX: [
function() { return += + r(-screenWidth/2.5, screenWidth/2.5) },
function() { return r(0, screenWidth) }
],
translateY: [
function() { return += + r(-screenHeight/2.75, screenHeight/2.75)
},
function() { return r(0, screenHeight) }
],
translateZ: [
function() { return += + r(translateZMin, translateZMax) },
function() { return r(translateZMin, translateZMax) }
]
}, { duration: 6000 })
Its time to examine the translate animations, which individually translate the circle
elements positions within the demos 3D space. All three axes are animating from a
randomized start value toward a randomized end value. The value operator, which consists
of the plus sign followed by the equals sign (+=), tells the animation engine to animate
properties incrementally from their starting values. In other words, the += value operator
instructs the animation engine to treat the ending value as a relative value. In contrast, the
default behavior of an animation engine is to interpret an end value in absolute terms.
As with opacity, this code section leverages force-feeding and value functions for
their expressivity and performance benefits. In particular, the circles movement is
constrained within ranges relative to the screen dimensions for the X and Y axes, and
relative to the predefined min and max depth values for the Z-axis. (As a reminder, these
values were set in the Animation setup section.) In the case of the X and Y axes, theres an
arbitrary fudge factor (notice the division by 2.75) to reduce how spread out the elements
animate. This value is simply a creative decision; tweak it to suit your aesthetic
preference.
Finally, the options object specifies that this entire animation should occur over a
duration of 6000ms.
Reverse command
After the primary Velocity animation call, the chain continues with a call to Velocitys
reverse command. Reverse does exactly what it sounds like it: it animates the target
elements back to their initial values prior to the previous Velocity call taking place. In this
unique case, since start values have been force-fed into the previous Velocity call, those
are the start values that reverse will animate back toward.
One of my reasons for including the reverse command in this demo is to extend the
demos overall animation duration with a single line of maintainable and expressive code.
(While you could double the duration of the animation from 6000ms to 12000ms, this
would result in slowing down the movement of the circles.) The convenience of the
reverse command is avoiding having to respecifyby handall of the animation start
values. It would have been a huge mess to accomplish this manually since you would have
had to first store all of the randomly generated start values into memory so you could
animate back to them. Hence, reverse is yet another great Velocity feature that allows the
demo to accomplish a lot with just a few lines of code.
Velocitys reverse command defaults to the options object used in the previous Velocity
callincluding its duration, easing, and so on. In this case, since the previous call
used a duration of 6000ms, so will the reverse call. The reverse command also lets you
specify a new options object to extend onto the previous one. This demo uses a new easing
type of easeOutQuad for added motion design flair in the animations reverse direction.
Tip
To preview the behavior of the popular easing types, visit http://easings.net.
When the reverse animation completes, a final Velocity call fades the elements out of
view by transitioning their opacity values to 0 over a duration of 2000ms. This
completes the demo by leaving the browsers canvas in the same visual state it began in:
clean and empty! Your work here is done.
Wrapping up
From force-feeding, to value functions, to reverse, this walkthrough has illustrated the
power of the Velocity animation engine. Hopefully, this chapter has convinced you that
this books focus on Velocity was worthwhile. In fewer than 75 lines of terse, legible, and
performant code, youve created a rich 3D scene unlike anything youve seen before in
pure HTML.
Let this demo serve as a concrete example of just how simple intricate-looking
animations can actually beespecially when you use the right tools and employ best
practices. My hope is that this book has distilled the beautiful animation work youve seen
across the web into a set of tenets that are easy to grasp and follow in pursuit of your own
motion design.
Now, go and design some beautiful websites and apps! Once youve put together
something cool, show me on Twitter: twitter.com/shapiro.
Index
Symbols and Numbers
$.animate() 13
3D
CSS primer on 156
transforms 96
A
Adobe After Effect, animating text and 80
Adobe Photoshop, SVG and 104
Alerts, leveraging user response 4243
Android
purchasing older devices from eBay 144
realities of web performance 118
Animation demo
behaviors 148149
code section for animation setup 153154
code section for circle animation 160164
code section for circle creation 154155
code section for container animation 156159
code structure 150152
overview of 147
review 165
Animation libraries
bypassing jQuery 6
page scrolling functions 7
SVG support 108
types of 14
Animation reversal, performance features of JavaScript 78
Animations. See also Motion design
breaking into steps 4849
effects on neighboring elements 130
B
backgroundColor property, Velocity support for CSS color properties 3132
backwards option, benefits in text animation 9293
Baselines, load testing and 120
Batching DOM additions
code section for circle creation 155
problem 126127
solutions 127128
begin option, Velocity 24
Bzier curves, easing values in Velocity 22
Blast.js
customClass option 8586
delimiter option 85
generateValueClass option 8687
how it works 8384
installing on pages 8485
preparing text elements using 8283
reverse option 8889
tag option 8788
Blue, Velocity support for CSS color properties 3132
body tag, installing Blast and 84
Bold text, tag option in Blast and 88
Boolean values, generateValueClass option in Blast 8687
borderColor property, Velocity support for CSS color properties 3132
border-radius set property, in behavior of animation demo 148
Bottlenecks
problem 133
solutions 133134
Bottom line, performance affecting 117
box-shadow property, CSS
in behavior of animation demo 148
overview of 138
Browsers
animations on older browsers problem 139
animations on older browsers solution 139140
bottlenecks and 133
finding performance threshold early on 141143
positional attributes vs. transforms and 110
realities of web performance 118
support for older versions 4
BrowserStack.com, testing browsers on 142
Buttons, uses of SVG 109
C
Callback functions, begin and complete options in Velocity 24
Chaining
effects and 69
using Velocity with jQuery and 16
in Velocity 20
character delimiter, Blast.js 82, 85
Chrome, realities of web performance 118
circle element
in behavior of animation demo 148
code section for circle animation 160164
code section for circle creation 154155
code structure for animation demo 153154
SVG presentational attributes 106
SVG styling 106
Classes
customClass option in Blast 8586
generateValueClass option in Blast 8687
Code/coding techniques
code section for animation setup 153154
code section for circle animation 160164
code section for circle creation 154155
code section for container animation 156159
code structure for animation demo 150152
creating images through code in SVG 104
optimized approach to organizing sequenced animations 6668
optimized approach to packaging effects 7072
optimized approach to separating styling from logic 6065
standard approach to organizing sequenced animations 6566
standard approach to packaging effects 69
standard approach to separating styling from logic 5960
what good code looks like 57
color property, Velocity support for CSS color properties 3132
Colors
D
Data transfer indicators, preview options in motion design 41
Debouncing, event handlers 135136
delay option, Velocity 26
Delay values
staggering durations and 91
timing multipliers and 73
Delimiters, Blast.js 82, 85
Design techniques. See also Motion design
page scrolling in Web design 7
timing multipliers 7374
VMD (Velocity Motion Designer) 7476
Device Lab 142
display option, Velocity 2728
div
in behavior of animation demo 148
Blast.js 82
HTML elements 83
tag option in Blast 88
DOM (Document Object Model)
batching DOM additions for improved performance 126128, 155
layout thrashing problem 121122
layout thrashing solution 122123
retrieving raw DOM elements 3334
SVG elements as DOM elements 104
duration option, Velocity 21
Durations
limiting in motion design 45
staggering 91
E
Easing options, Velocity 2123
eBay, purchasing older devices from 144
Effects
fade effect in UI pack 91
fanciful effects in text 96
flourishes in text 9798
optimized coding approach to packaging 7072
standard coding approach to packaging 69
transition.fadeOut effect in UI pack 92
Elegance aspects, of motion design
breaking animation into steps 4849
flowing from triggering elements 49
graphics use 50
not being frivolous 47
opacity use 48
overview of 3940
staggering animations 49
using appropriate personality features 4748
Element nodes, HTML 83
Elements
animation effects on neighboring elements 130132
circle element. See circle element
fine-grained control of Blast elements 94
flowing from triggering elements 49
HTML element manipulation 148
image rendering problems 137
image rendering solutions 137138
JEOs (jQuery element objects) 123124, 126128
preparing text elements for animation using Blast.js 8283
retrieving raw DOM elements 3334
F
Fade effect, in UI pack 91
Familiarity, use of conventions in making design choices 41
fill, SVG
presentational attributes 105
styling 107
Flags, leveraging user response 4243
Flourishes, in text 9798
Flow, creating from triggering elements 49
Force-feeding feature (Velocity), for avoiding layout thrashing problem 124125
Frivolous design, uses and abuses of 47
G
generateValueClass option, Blast.js 8687
gets
JEOs as culprit in layout thrashing 123124
layout thrashing and 121122
Global timing multipliers 7374
Gradients, CSS 138
Graphics
in elegant motion design 50
SVG and 104, 109
Green, Velocity support for CSS color properties 3132
GSAP animation library 14
H
Height, SVG presentational attributes 105
I
Images
creating through code in SVG 104
rendering problems 137
rendering solutions 137138
sneaky image problems 139
sneaky image solutions 139140
img element 138
Incentives, visceral nature of interactions and 43
Infinite looping, in Velocity 2526
See also Loops
Inkscape 104
Inline status indication, engaging users in tasks 42
In-progress indicators, preview options in motion design 4142
Internet Explorer
animations on older browsers problem 139
finding performance threshold early on 141143
positional attributes vs. transforms and 110
realities of web performance 118
iOS, purchasing older devices from eBay 144
Irreversible actions, indicators for 43
J
Janks (stutters), layout thrashing and 121
JavaScript vs. CSS
L
Latency, search engine performance and 117
Layout thrashing
force-feeding feature in Velocity for avoiding 124125
JEOs (jQuery element objects) as culprit in 123124
problem 121122
solutions 122123
Load testing, realities of web performance and 120
Logic
optimized coding approach to separating from styling 5960
M
Maintenance, of workflows 9
Markup, SVG 105106
Max values, code section for animation setup 154
Min values, code section for animation setup 154
Mock feature, Velocity 74
Motion design
alerts and flags for leveraging user response 4243
appropriate personality features 4748
breaking animation into steps 4849
conventions in making design choices 41
engaging users in tasks 42
experimenting repeatedly 5152
flowing from triggering elements 49
graphics use 50
indicators of severity of irreversible actions 43
limiting animations 45
limiting durations 45
mirroring animations 44
not being frivolous 47
opacity use 48
overview of 37
previewing outcomes 41
reducing concurrency 43
reducing variety 44
review 53
staggering animations 49
utility and elegance of 3940
UX (user experience) improved by 38
visceral nature of interactions 43
Mozilla Developer Network, directory of SVG elements 114
Multi-animation sequences, solutions to concurrency issues 134
Multipliers, timing multipliers as design technique 7374
O
Opacity
animation of 161
flourishes in text 9798
going beyond overuse of 48
performance benefits of using instead of color 132
opacity property 161
outlineColor property, Velocity support for CSS color properties 3132
P
Page scrolling, performance features of JavaScript 7
See also scroll command
Performance
animation effects on neighboring elements problem 130
animation effects on neighboring elements solution 131132
animations on older browsers problem 139
animations on older browsers solution 139140
batch DOM additions problem 126127
batch DOM additions solutions 127128
bottleneck concurrency problems 133
bottleneck concurrency solutions 133134
features of JavaScript 6
finding performance threshold early on 141143
R
Random numbers, code section for animation setup 153
Red, Velocity support for CSS color properties 3132
resize events
S
Safari, realities of web performance 118
Scalable vector graphics. See SVG (scalable vector graphics)
Scale, CSS transform property 32
scroll command
overview of 3031
Velocity page scrolling 7
scroll events
performance problems 135
performance solutions 135136
Scrolling, page animation and 137
Search engines, latency and 117
sentence delimiter, Blast options 8485
Sequence running, in UI pack 65
Sequenced animations
optimized coding approach to organizing 6668
standard coding approach to organizing 6566
sets, layout thrashing and 121122
setup
code section for animation setup 153154
code structure for animation demo 150
Shadow properties, CSS 138
Shorthand features, in Velocity 20
T
Tables, HTML elements 83
tag option, Blast.js 8788
Text animation
customClass option in Blast 8586
delimiter option in Blast 85
flourishes in text 9798
generateValueClass option in Blast 8687
how Blast.js works 8384
installing Blast on page 8485
overview of 79
preparing text elements using Blast.js 8283
replacing existing text 90
reverse option in Blast 8889
review 100
staggering option 91
standard approach to 80
tag option in Blast 8788
transitioning individual text parts 9495
U
UI (user interface)
conventions in making design choices 41
motion design improving user experience 38
UI animation libraries 14
UI animation workflow 65
UI pack
fade effect in 91
getting and installing 65
optimized coding approach to packaging effects 7072
stagger feature in 133134
transition.fadeOut effect 92
transitioning text fancifully 96
Unit types, values in Velocity 1920
User experience. See UX (user experience)
User interface. See UI (user interface)
Utility aspects, of motion design
alerts and flags for leveraging user response 4243
conventions in making design choices 41
engaging users in tasks 42
indicators of severity of irreversible actions 43
limiting animations 45
limiting durations 45
mirroring animations 44
overview of 3940
previewing outcomes 41
reducing concurrency 43
reducing variety 44
visceral nature of interactions 43
Utility function, Velocity 66
UX (user experience)
motion design improving 38
performance affecting 117
physics-based motion in JavaScript enhancing 8
V
Values
code section for animation setup 154
value functions 161
Velocity 1920
Variety, reducing in motion design 44
Velocity
animation demo. See Animation demo
arguments 1618
begin and complete options 24
chaining 20
color options 3132
compared with jQuery 13
containing animation logic within 29
delay option 26
display and visibility options 2728
downloading and installing 15
duration option 21
easing options 2123
force-feeding feature for avoiding layout thrashing 124125
loop option 2526
mock feature 74
optimized coding approach to organizing sequenced animations 6668
page scrolling functions 7
passing properties in SVG animations 109
physics-based motion 8
properties 1819
resource for SVG attributes and styling properties 114
reverse command 30
review 3334
scroll command 3031
transform property 3132
types of animation libraries 14
UI pack 65
using with jQuery 16
using without jQuery 3334
values 1920
Velocity Motion Designer (VMD) 7476
Video. See also Images
image rendering problems 137
image rendering solutions 137138
Visibility
replacing existing text 90
transitioning text out of view 9193
transitioning text visibility 80
visibility option, Velocity 2728
Visual processing, leveraging primal instincts in motion design 4243
VMD (Velocity Motion Designer) 7476
W
Web design, use of page scrolling in 7
Web performance, realities of 118120
Width, SVG presentational attributes 105
word delimiter, Blast options 85
Workflows
CSS appropriate uses 5758
CSS issues 5657
maintainability of 9
optimized coding approach to organizing sequenced animations 6668
optimized coding approach to packaging effects 7072
optimized coding approach to separating styling from logic 6065
overview of 55
review 77
standard coding approach to organizing sequenced animations 6566
standard coding approach to packaging effects 69
standard coding approach to separating styling from logic 5960
timing multipliers as design technique 7374
VMD (Velocity Motion Designer) 7476
X
x value, SVG presentational attributes 105
Y
y value, SVG presentational attributes 105
Code Snippets