CSS Animations
Orchestrated

CSS
IS
AWES...
text-overflow: ellipsis;
CSS Animations
What comes to mind?
Difficult to compose/sequence animations easily





David Khourshid
@davidkpiano
Codepen, Github, Twitter

Stages of Learning Music
Wow, this is fun!
Eh, maybe later.
Check it out, eyes closed!
I want to quit.
Time to get serious!
Stages of Learning CSS
Wow, that was easy!
I'll finish the styling later.
Look at all those Codepens!
Screw it, Bootstrap
Time to get serious!
- CSS Tooling: we're getting there
 - Preprocessors: use them!
 - Take notes
 - Keep an open mind
 - Relax: code in a thermal bath
 
Preparation
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
Rhythm
- Proportional durations
 - Human Processor Model: 230ms
 - Match duration to experience
 
    Communicate animation efficiently, yet effectively
Quickly, yet with meaning
$duration-slow: 1s;
$duration-medium: $duration-slow / 2;
// 500ms
$duration-fast: $duration-medium / 2;
// 250ms
    Melody
- Single voice
 - Pitch, timbre, texture, loudness
 - Phrases and dynamics
 

Melody
Harmony
Melody in
Animation
- Timing functions (easing curves)
 - Focal point and meaning
 - Entrance, emphasis, exit
 

// 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
Harmony
- A collection of simultaneous notes
 - Consonance and dissonance
 - Gives context to melody
 
Harmony in
Animation
- Multiple simultaneous effects
 - Gives context to focal point
 - Consonance and dissonance
 - Material Design - Motion & Choreography
 

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;
  }
}
    CSS
CONF 2016
Groups and Sequences
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
Effects can be nested
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;
  }
}
    Group Effects

$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),
  ),
  // ...
);
    Sequence Effects
@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};
        }
      }
    }
  }
}
    
...what?
from 0%
to 100%
50%
0ms
600ms
1400ms
2400ms
 percentage($offset / $duration)
- 0ms / 2400ms = 0%
 - 600ms / 2400ms = 25%
 - 1400ms / 2400ms = 58.33333333333333333333333333%
 - 2400ms / 2400ms = 100%
 
Total duration
Start delay
Current duration
End delay
- Start delay = sum of past (durations + start delays)
 - End delay = total duration - (start delay + current duration)
 
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!

CSS
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
  }
}Staggers and Loops
.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%);
  }
}
    Staggers and Loops
$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%);
        }
      }
    }
  }
}
    Staggers and Loops
0%
100%
50%
Composition
.square {
  animation: rotate 1s linear infinite;
}
.square-container {
  animation: slide-left 2s $easing infinite;
}
    Guidelines
For CSS Animation
Rhythm
Keep durations short yet meaningful
200ms - 500ms
Choose proportional durations
Use $variables
Melody
Choose natural timing functions (easings)
Accelerate from 0, decelerate to 0
Enter, Emphasis, Exit
cubic-bezier(_, 0, _, 1);
Tweak in @keyframes
Harmony
Identify the focal (main) effect
Avoid superfluous effects
Similar durations, similar easings
Groups, Sequences, Staggers, Loops
Animation-delay is not your friend
Harmony
Start-offset, duration, end-offset
percentage($offset / $duration)
Use @for loops
Use @each loops with $maps
Composition
Always keep transforms together
Independent transforms: use layers (for now)
Separate animations for color, etc.
CSS Animations are Awesome
Experiment & Never Stop Learning








Thank you!
@davidkpiano
CSS Animations, Orchestrated
By David Khourshid
CSS Animations, Orchestrated
- 29,349