Today's Focus
Not about why to animate
Why this new API might be useful
Basics of how to use the API
More about comparing and contrasting with current methods to animate
So yes, we'll get a bit technical. And if you aren't familiar with any of the current ways/whys to animate, I encourage you to check them out, and I know there are a couple other CSS Summit sessions joining in the animation fun, largely sandwiching this session
Honestly, right now there are few resources/tutorials discussing this API, so I'm learning it too... I have no hand in directly making or defining this.
How do we animate on the Web?
jQuery animate()
requestAnimationFrame
Libraries such as GreenSock and Velocity
CSS Transitions and Keyframe Animations
SVG Animation
Straight up setTimeout/setInterval
Discuss Pros and Cons as well (why we love/hate)
Easy, but slow (comment on jank)
Lets browser control to optimize, but can be imprecise
Have resources and knowledge to optimize, but third party and requires maintaining libraries
Can be hardware accelerated and precise, but are statically defined. Can be hard to dictate exact paths of motion and dynamic starts and destinations
SVG... powerful, complicated, and limited to SVG (not other HTML content)
Lots of things.
Enter the Web Animations API
W3C Editor's Draft
Unite the various SVG/CSS/JS ways to animate
WAA?
The benefits of SVG/CSS/JS
Off main-thread (hardware acceleration)
Dynamic values
Timelines and playback control
Callbacks
... [at end] Before we talk about how we start using this... let's talk specifically about what is available right now.
What's available today?
Browsers have started implementing and exploring
How Chrome is Implementing the API
Polyfill on GitHub (in use on Google's Polymer Project)
Animate an element returning an AnimationPlayer
Chrome has reworked their renderer to use the same code for both CSS and these new JS animations. So either way you choose will have the same underlying code running - nice. They are taking the "unite the various methods" part of this API to heart
AnimationPlayer
play()
, pause()
, finish()
, and cancel()
playState
reverse()
currentTime
playbackRate
finish() takes you to end state (and calls onfinish), cancel() removes all signs of playing
running, paused, finished, idle
We will be jumping into all of these as we go along. These also represent the primary pieces that are available to us today, in some browsers and with a polyfill
Create a Player
Transitioning from one state to another state, with transform
var player = document.getElementById('toAnimate').animate([
{ transform: 'scale(1)' },
{ transform: 'scale(.6)' }
], {
duration: 700, //milliseconds
iterations: Infinity, //or a number
direction: 'normal', //'alternate', 'reverse', ...
fill: 'forwards', //'backwards', 'both', 'none', 'auto'
delay: 10, //milliseconds
easing: 'ease-in-out', //'linear', 'ease-in', ...
});
Declare a variable for the player, find the element we want to animate, call animate on it with two parameters. First parameter is an array of KeyFrames. Second parameter is a collection of Timing Effects. Some things in here might look familiar to CSS Transitions and Animations...
Create a Player
Animating multiple frames, with transform and opacity
var player = document.getElementById('toAnimate2').animate([
{ transform: 'scale(1)', opacity: 1, offset: 0 },
{ transform: 'scale(.5)', opacity: .5, offset: .333333 },
{ transform: 'scale(.667)', opacity: .667, offset: .666667 },
{ transform: 'scale(.6)', opacity: .6, offset: 1 }
], {
duration: 700,
easing: 'linear',
delay: 0,
iterations: 3,
direction: 'alternate',
fill: 'forwards'
});
Keyframes: pass in the properties we want to change (transform, opacity), and optionally an offset and easing
No offset means they are evenly distributed (in this case: 0, 33%, 67%, 100%)
So animate returns an AnimationPlayer object... this player is what we will ultimately be calling if we want to modify timelines and controls.
Create a Player
Animating multiple frames, with transform and opacity
var player = document.getElementById('toAnimate2').animate([
{ transform: 'scale(1)', opacity: 1 },
{ transform: 'scale(.5)', opacity: .5 },
{ transform: 'scale(.667)', opacity: .667 },
{ transform: 'scale(.6)', opacity: .6 }
], {
duration: 700,
easing: 'linear',
delay: 0,
iterations: 3,
direction: 'alternate',
fill: 'forwards'
});
Keyframes: pass in the properties we want to change (transform, opacity), and optionally an offset and easing
No offset means they are evenly distributed (in this case: 0, 33%, 67%, 100%)
So animate returns an AnimationPlayer object... this player is what we will ultimately be calling if we want to modify timelines and controls.
Pretty much looks like...
@keyframes emphasis {
0% {
transform: scale(1); opacity: 1; }
33.3333% {
transform: scale(.5); opacity: .5; }
66.6667% {
transform: scale(.667); opacity: .667; }
100% {
transform: scale(.6); opacity: .6; }
}
#toAnimate2 {
animation: emphasis 700ms linear 0s 3 alternate forwards;
}
But if it already has an equivalent in CSS...
Keep benefits of CSS, such as hardware acceleration
Variables (vs. Declarative)
Finer control
Player controls
CSS transitions/keyframes are declarative statically defined... Go from point A to point B. If you sometimes want to go to point C you need to set up completey new keyframes. And for D, and E, and F, and even G...
Instead of toggling classes and not being certain what happens if the class changes again before the animation completes (does it animate back, does it stop in tracks, does it simply revert back), you can now know more about what will happen as we will discuss next
Player Timeline
var player = element.animate(/* animation */);
player.currentTime = 200;
Read the current time... or set it to jump
Sync multiple animations together
Max value is delay + (duration * iterations)
CodePen: API Sync
CodePen Collection
Spec also defines startTime... but the spec is confusing, and how it differs from currentTime is unclear. There is only one good example of it in use from Rachel Nabors, as seen in the CodePen Collection
Player Controls and playStates
var player = element.animate(/* animation */);
console.log(player.playState); //"running"
player.pause(); //"paused"
player.play(); //"running"
player.cancel(); //"idle"... jump to original state
player.finish(); //"finished"...jump to end state
CodePen Demo (Walking Circles)
"pending" state is also specified, but spec is unclear in its true meaning
Wait for Demo until next screen
Player PlaybackRate
var player = element.animate(/* animation */);
player.playbackRate = .25; //.25x speed
Slow it down or speed it up
currentTime will account for playbackRate
CodePen Demos Walking Circles | Countdown
If you have the same two animations except the playback rate has been doubled on one, the currentTime will always be twice as far on the doubled rate player.
What are the Catches?
Native browser support (caniuse.com )
Spec not final / Polyfill changes
Some minor inconsistencies with CSS
Some of the more exciting features are yet to come...
Chrome supports element.animate and some timeline controls
Firefox in the latest Developer edition, or behind a flag in the regular edition
In CSS could specify multiple offsets with the same properties...
What’s Next?
MotionPath
spacing
GSAP and SMIL are the best ways to accomplish motion path now, also coming to CSS animations.
So have we finally done it?
Did we solve all our animation needs?
No
But let's be thankful for progress... and polyfills
Of course not... but hey, it's all good progress. Trying this stuff out now can help the spec going forward and drive its implementation, support, and features. Getting more available at the browser level to improve performance and control is a good thing.