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

image/svg+xml

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
image/svg+xml

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

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