Orchestrated
CSS
IS
AWES...
text-overflow: ellipsis;
What comes to mind?
Difficult to compose/sequence animations easily
@davidkpiano
Codepen, Github, Twitter
Wow, this is fun!
Eh, maybe later.
Check it out, eyes closed!
I want to quit.
Time to get serious!
Wow, that was easy!
I'll finish the styling later.
Look at all those Codepens!
Screw it, Bootstrap
Time to get serious!
Principle: Powerful languages inhibit information reuse.
Good practice: Use the least powerful language suitable for expressing information, constraints or programs on the World Wide Web.
Rhythm
Melody
Harmony
Form
Durations & Delays
Effects and Easing Curves
Groups and Sequences
Themes and Storyboarding
Quickly, yet with meaning
$duration-slow: 1s;
$duration-medium: $duration-slow / 2;
// 500ms
$duration-fast: $duration-medium / 2;
// 250ms
Melody
Harmony
// Entrance easing
$easing-enter: cubic-bezier(0, 0, 0.5, 1);
// Emphasis/general easing
$easing: cubic-bezier(0.5, 0, 0.5, 1);
// Exit easing
$easing-exit: cubic-bezier(0.5, 0, 0, 1);
$easing: cubic-bezier(_, 0, _, 1);
Start
End
body.active {
// Harmonic animations
.heading, .subheading {
animation-duration: $duration-normal;
animation-timing-function: $easing-enter;
animation-fill-mode: both;
}
.heading {
animation-name: slide-up;
}
.subheading {
animation-name: slide-down;
animation-delay: $duration-fast;
}
}
CONF 2016
Composing Harmonic Animations
Single effect
Multiple keyframes
Multiple effects
Same starting time
Multiple effects
Starting time based on previous starting time
KeyframeEffect()
GroupEffect() *
SequenceEffect() *
Group
Sequence
Sequence
Group
This requires math
body.week-selected {
.label.-vacation,
.label.-walk,
.label.-fishing,
.label.-weekend,
.label.-custom {
animation-name: slide-right;
// Same delays, proportional durations
animation-delay: $duration-fast;
animation-duration: $duration-normal;
}
.label.-custom {
animation-duration: $duration-slow;
}
}
$animations: (
// ...
'nose': (
// resting position
(4s, 5s, 7s): rotateY(-4deg),
// nose down
4.5s: rotateY(-4deg)
rotateX(-3deg),
// fox looks left
(7.5s, 9s):
rotateX(-3deg)
rotateY(-28deg)
rotateZ(-11deg),
// fox looks right
(9.5s, 12s): rotateY(7deg),
// fox looks straight ahead
13s: rotateY(0),
),
// ...
);
@each $animation-name, $animation in $animations {
// keyframe declaration
@keyframes #{$animation-name} {
@each $offsets, $transform in $animation {
@each $offset in $offsets {
// offset declaration block
#{percentage($offset / $duration)} {
// transform property
transform: #{$transform};
}
}
}
}
}
from 0%
to 100%
50%
0ms
600ms
1400ms
2400ms
percentage($offset / $duration)
Total duration
Start delay
Current duration
End delay
4s
9s
12s
@keyframes orange {
#{percentage(4s / 12s)} {
transform: translateX(0);
}
#{percentage(9s / 12s)} {
transform: translateX(100px);
}
}
@keyframes orange {
0%, #{percentage(4s / 12s)} {
transform: translateX(0);
}
#{percentage(9s / 12s)} {
transform: translateX(100px);
}
}
@keyframes orange {
0%, #{percentage(4s / 12s)} {
transform: translateX(0);
}
#{percentage(9s / 12s)}, 100% {
transform: translateX(100px);
}
}
animation-delay
is not your friend
animation-delay: 4s .................
animation-delay: 9s ....................................................................................
This will work, with the right fill modes
.box {
animation:
first 2s backwards,
second 4s 4s none,
third 3s 9s forwards;
}
first 2s
second 4s
third 3s
animation-delay
is not your friend
animation-delay: 4s .................
animation-delay: 9s ....................................................................................
first 2s
second 4s
third 3s
Expectation
Reality
Delays do not repeat!
animation-delay
is not your friend
start-offset: 4s .........................
start-offset: 9s .............................................................................................
first 2s
second 4s
third 3s
$duration: 12s;
@keyframes first-second-third {
from {
// start first animation
}
#{percentage(2s / $duration)},
#{percentage(4s / $duration)} {
// end first animation
// begin second animation
}
// ... continued
// ... continued:
#{percentage(8s / $duration)},
#{percentage(9s / $duration)} {
// end second animation
// begin third animation
}
to {
// end third animation
}
}
animation-delay
is not your friend
start-offset: 4s .........................
start-offset: 9s .............................................................................................
first 2s
second 4s
third 3s
$duration: 12s;
@keyframes first-second-third {
from {
// start first animation
}
#{percentage(2s / $duration)},
#{percentage(4s / $duration)} {
// end first animation
// begin second animation
}
// ... continued
// ... continued:
#{percentage(8s / $duration)},
#{percentage(9s / $duration)} {
// end second animation
// begin third animation
}
to {
// end third animation
}
}
.dot {
animation: up-down 2s $easing both infinite;
@for $i from 1 through 3 {
&:nth-child(#{$i}) {
animation-delay: 0.2s * ($i - 1);
}
}
}
@keyframes up-down {
from, 75%, to {
transform: translateY(0);
}
25%, 50% {
transform: translateY(400%);
}
}
$duration: 2s;
$stagger: 0.2s;
.dot {
@for $i from 1 through 3 {
&:nth-child(#{$i}) {
$delay: percentage(
($stagger * ($i - 1)) / $duration);
animation:
dot-#{$i} $duration $easing infinite;
@keyframes dot-#{$i} {
from, to, 75%{
transform: translateY(0);
}
#{25% + $delay},
50% {
transform: translateY(400%);
}
}
}
}
}
0%
100%
50%
.square {
animation: rotate 1s linear infinite;
}
.square-container {
animation: slide-left 2s $easing infinite;
}
For CSS Animation
Keep durations short yet meaningful
200ms - 500ms
Choose proportional durations
Use $variables
Choose natural timing functions (easings)
Accelerate from 0, decelerate to 0
Enter, Emphasis, Exit
cubic-bezier(_, 0, _, 1);
Tweak in @keyframes
Identify the focal (main) effect
Avoid superfluous effects
Similar durations, similar easings
Groups, Sequences, Staggers, Loops
Animation-delay is not your friend
Start-offset, duration, end-offset
percentage($offset / $duration)
Use @for loops
Use @each loops with $maps
Always keep transforms together
Independent transforms: use layers (for now)
Separate animations for color, etc.
Experiment & Never Stop Learning
@davidkpiano