F u n w i t h t h e W e b A n i m a t i o n s A P I
Front Porch 2016
Dan Wilson | @dancwilson
Slides: http://danielcwilson.com/talks/2016/animations
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.
How do we animate on the Web?
Straight up setTimeout/setInterval
jQuery animate()
requestAnimationFrame
CSS Transitions and Keyframe Animations
SVG Animation
Libraries such as GreenSock
Discuss Pros and Cons as well (why we love/hate)
Lots of things.
Easy, but slow (comment on jank)
Lets browser control to optimize, but can be imprecise
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)
Have resources and knowledge to optimize, but third party and requires maintaining libraries
Enter the Web Animations API
W3C Editor's Draft
Unite the various SVG/CSS/JS ways to animate
The 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?
Chrome and Opera have pieces implemented
Firefox soon (currently in Nightly and Dev Editions)
How Chrome is Implementing the API
Polyfill available
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. Polyfill is used in Polymer.
Create an Animation
Transitioning from one state to another
var anim = 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 an Animation
Animating multiple frames, multiple properties
var anim = 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,
iterations: 30,
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 Animation 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 anim = element.animate(/* animation */);
anim.currentTime = 200;
Read the current time... or set it to jump
Sync multiple animations together
Max value is delay + (duration * iterations)
CodePen: API Sync
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
Controls and playStates
var anim = element.animate(/* animation */);
console.log(anim.playState); //"running"
anim.pause(); //"paused"
anim.play(); //"running"
anim.cancel(); //"idle"... jump to original state
anim.finish(); //"finished"...jump to end state
CodePen Demo (Walking Circles)
"pending" state is also specified
Wait for Demo until next screen
PlaybackRate
var anim = element.animate(/* animation */);
anim.playbackRate = .25; //.25x speed
Slow it down or speed it up
currentTime will account for playbackRate
CodePen Demos Walking Circles | Countdown
1x
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 | Feature Breakdown )
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 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...
CSS Motion Path
Animate along a path!
Chrome has initial support... still a lot to figure out
CodePen Collection
So have we finally done it?
Did we solve all our animation needs?
No
But let's be thankful for progress... and polyfills... and solid foundations...
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. It leaves time for the libraries to innovate in new areas while the basics get down to the native browser level.