Introduction to Animation on the Web

ZOOOOOOM! 🔍

Is everything big enough and are we in dark mode?

Housekeeping 🧹

  • Everyone is encouraged to have their cameras on
  • Session will be recorded and made available by the learning team in a few weeks
  • Content will also be available on my website after the session
  • We will stop for questions along the way and should have some time at the end
  • Animations may be a bit laggy due to MS Teams

🎞️ Animation on the Web 🌐

Things ✌️ Talk About

(the agenda)

  • Why do we need animations?
  • Animating in CSS
  • Principles of Animation
  • When to ignore all of this

Why do we need animations? 🤷

  • User Feedback
  • Draw attention to something
  • Highlight personality
  • Juicyness

☝️ A Quick Note on Custom Properties

These examples make extensive use of CSS Custom Properties so it's good to have a basic understanding of them

web-animations/custom-properties.css
.my-stuff {
  /* def */
  --my-color: red;
  --my-size: 12px;

  /* use */
  background-color: var(--my-color);

  /* default */
  height: var(--my-size, 24px);
  width: var(--some-undefined-value, 24px);
}

Animating in CSS 🧑‍💻

  • Transitions
  • Keyframes
  • View Transitions
  • Optimizing Animations

Transitions 🎢

  • Related to state changes
  • Control change of properties over time
  • Implicit transitions
    • Intermediate states defined by browser

Setting up a Transition 🔧

We need something to animate

web-animations/styles.css
.greeting {
  display: inline-block;
  text-transform: lowercase;
  padding: 0.5rem 1rem;
  background-color: var(--color-brand-muted);
  color: var(--color-on-base);
  cursor:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
      16 0,
    auto;
}

.hand {
  display: inline-block;
}
web-animations/index.html
<div class="wrapper">
  <div class="greeting">
    Hi there
    <span class="hand">👋</span>
  </div>
</div>
Hi there 👋

Using Transitions 👷

Questions?

web-animations/transition-simple.css
.greeting {
  display: inline-block;
  text-transform: lowercase;
  padding: 0.5rem 1rem;
  background-color: var(--color-brand-muted);
  color: var(--color-on-base);
  cursor:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
      16 0,
    auto;
}

.hand {
  display: inline-block;
}

.greeting {
  transition-property: all;
  transition-duration: 300ms;
  transition-delay: 100ms;
  transition-timing-function: ease-in;
}

.greeting:hover {
  transform: scale(1.1);
  background-color: var(--color-brand);
  color: var(--color-on-brand);
}
Hi there 👋

📏 Shorthand Syntax

web-animations/transition-simple-alt.css
.greeting {
  display: inline-block;
  text-transform: lowercase;
  padding: 0.5rem 1rem;
  background-color: var(--color-brand-muted);
  color: var(--color-on-base);
  cursor:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
      16 0,
    auto;
}

.hand {
  display: inline-block;
}

.greeting {
  /* shorthand */
  transition: all 300ms 100ms ease-in;
}

.greeting:hover {
  transform: scale(1.1);
  background-color: var(--color-brand);
  color: var(--color-on-brand);
}
Hi there 👋

Multi Property Transitions ♾️

web-animations/transition-properties.css
.greeting {
  display: inline-block;
  text-transform: lowercase;
  padding: 0.5rem 1rem;
  background-color: var(--color-brand-muted);
  color: var(--color-on-base);
  cursor:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
      16 0,
    auto;
}

.hand {
  display: inline-block;
}

.greeting {
  transition-property: transform, color, background-color;
  transition-duration: 300ms, 100ms, 100ms;
  transition-delay: 0ms, 300ms, 300ms;
  transition-timing-function: ease-in, ease-out, ease-in-out;
}

.greeting:hover {
  transform: scale(1.1);
  background-color: var(--color-brand);
  color: var(--color-on-brand);
}
Hi there 👋

🤏 Multi Property Transition Shorthand

web-animations/transition-properties-alt.css
.greeting {
  display: inline-block;
  text-transform: lowercase;
  padding: 0.5rem 1rem;
  background-color: var(--color-brand-muted);
  color: var(--color-on-base);
  cursor:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
      16 0,
    auto;
}

.hand {
  display: inline-block;
}

.greeting {
  transition:
    transform 300ms 0ms ease-in,
    color 100ms 300ms ease-out,
    background-color 100ms 300ms ease-in-out;
}

.greeting:hover {
  transform: scale(1.1);
  background-color: var(--color-brand);
  color: var(--color-on-brand);
}
Hi there 👋

Combining Transitions 🤝

web-animations/transition-hand.css
.greeting {
  display: inline-block;
  text-transform: lowercase;
  padding: 0.5rem 1rem;
  background-color: var(--color-brand-muted);
  color: var(--color-on-base);
  cursor:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
      16 0,
    auto;
}

.hand {
  display: inline-block;
}

.greeting {
  transition:
    transform 300ms 0ms ease-in,
    color 100ms 300ms ease-out,
    background-color 100ms 300ms ease-in-out;
}

.greeting:hover {
  transform: scale(1.1);
  background-color: var(--color-brand);
  color: var(--color-on-brand);
}

.greeting .hand {
  transition: transform 100ms 0ms ease-out;
  transform-origin: bottom right;
}

.greeting:hover .hand {
  transition-duration: 300ms;
  transition-delay: 400ms;
  transform: rotate(30deg);
}
Hi there 👋

Timing ⏱️ Functions

web-animations/transition-timing.css
.greeting {
  display: inline-block;
  text-transform: lowercase;
  padding: 0.5rem 1rem;
  background-color: var(--color-brand-muted);
  color: var(--color-on-base);
  cursor:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
      16 0,
    auto;
}

.hand {
  display: inline-block;
}

.greeting {
  transition-property: color, transform;
  transition-duration: 1s;
  transition-timing-function: var(--timing-function);
}

.greeting:hover {
  transform: scale(1.2);
  background-color: var(--color-brand);
  color: var(--color-on-brand);
}
Hi there 👋

⏪ Recap Transitions

  • Syntax for Transitions
  • Defining transitions based on DOM state
  • Transitioning multiple properties
  • Shorthand syntax
  • Combining transitions
  • Timing functions

Animations 🎞️

  • Run as soon as the element or class is added
  • More complex animations possible
  • Can be independent of state
  • Implicit or Explicit
    • We can define intermediate states

Using Animations 📹

Questions?

web-animations/animation-simple.css
.greeting {
  display: inline-block;
  text-transform: lowercase;
  padding: 0.5rem 1rem;
  background-color: var(--color-brand-muted);
  color: var(--color-on-base);
  cursor:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
      16 0,
    auto;
}

.hand {
  display: inline-block;
  transform-origin: bottom right;

  /* basic properties */
  animation-delay: 100ms;
  animation-duration: 500ms;
  animation-timing-function: ease-in-out;

  /* keyframes name */
  animation-name: hand-wave;

  /* iterations */
  animation-iteration-count: infinite;

  /* direction */
  animation-direction: alternate;

  /* completion state */
  animation-fill-mode: forwards;
}

@keyframes hand-wave {
  from {
    transform: rotate(0deg);
  }

  to {
    transform: rotate(30deg);
  }
}
Hi there 👋

State Based Animations 🔛

web-animations/animation-hover.css
.greeting {
  display: inline-block;
  text-transform: lowercase;
  padding: 0.5rem 1rem;
  background-color: var(--color-brand-muted);
  color: var(--color-on-base);
  cursor:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
      16 0,
    auto;
}

.hand {
  display: inline-block;
  transform-origin: bottom right;

  animation-delay: 100ms;
  animation-duration: 500ms;
  animation-timing-function: ease-in-out;
  animation-name: hand-wave;
  animation-iteration-count: infinite;
  animation-direction: alternate;
  animation-fill-mode: both;

  /* state */
  animation-play-state: paused;
}

/* hover */
.greeting:hover .hand {
  /* state */
  animation-play-state: running;
}

@keyframes hand-wave {
  from {
    transform: rotate(0deg);
  }

  to {
    transform: rotate(30deg);
  }
}
Hi there 👋

Multi Property Animations 🍿

web-animations/animation-properties.css
.greeting {
  display: inline-block;
  text-transform: lowercase;
  padding: 0.5rem 1rem;
  background-color: var(--color-brand-muted);
  color: var(--color-on-base);
  cursor:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
      16 0,
    auto;
}

.hand {
  display: inline-block;
  transform-origin: bottom right;

  /* basic properties */
  animation-duration: 1s;
  animation-iteration-count: infinite;

  /* multi */
  animation-name: hand-wave-multi;
  animation-play-state: paused;
}

.greeting:hover .hand {
  animation-play-state: running;
}

@keyframes hand-wave-multi {
  0% {
    transform: rotate(0deg);
  }

  15% {
    scale: 150%;
    transform: rotate(0deg);
    translate: 0px -8px;
  }

  50% {
    scale: 150%;
    transform: rotate(30deg);
    translate: 0px -8px;
  }

  85% {
    scale: 150%;
    transform: rotate(0deg);
    translate: 0px -8px;
  }

  100% {
    transform: rotate(0deg);
  }
}
Hi there 👋

⏪ Recap - Animations

  • Syntax for Animations
  • Syntax for Keyframes
  • Defining animations based on DOM state
  • Animating multiple properties

View 🕶️ Transitions

  • Triggered by JS
  • Transitions content as well as properties
  • Can be used across navigations (browser support in progress)

Triggering a Transition ✅

Questions?

web-animations/ViewTransitions.astro
<script> 
  const words = [
    "pale",
    "dangerous",
    "secret",
    "madly",
    "sharp",
    "mammoth",
    "overrated",
    "painful",
    "ill-informed",
    "dizzy",
    "ambitious",
    "stable"
  ]

  const random = () =>  words[Math.floor(Math.random()*words.length)].toUpperCase();

  const handleWrapperClicked = (wrapper) => () => {
    // updateCallback 
    document.startViewTransition(() => {
      const content = wrapper.querySelector('.view-transitions-content')

      content.classList.toggle('inverted')
      content.innerHTML = random()
    })
  }

  // wait for all snippets to initialize
  setTimeout(() => {
    const wrappers = document.querySelectorAll('.view-transitions-wrapper')
    for (const wrapper of wrappers) {
      // trigger
      wrapper.addEventListener('click', handleWrapperClicked(wrapper))
    }
  }, 1000)
</script>

<style is:global>
  .view-transitions-wrapper {
    overflow: hidden;
  }

  .view-transitions-content {
    padding: 1rem;
    background-color: var(--color-brand);
    user-select: none;
    margin: 0;

    &.inverted {
      filter: invert();
    }
  }
</style>

The Default Transition 😐

  • 2 Different transitions
    • Fades old content out
    • Fades new content in
web-animations/view-transitions.html
<div class="view-transitions-wrapper">
  <h1 class="view-transitions-content">CONTENT</h1>
</div>

CONTENT

Understanding the Transition 🤔

Questions?

web-animations/view-transitions-slide.css
/* assign */
.view-transitions-content {
  view-transition-name: content-transition;
}

/* old */
::view-transition-old(content-transition) {
  animation: content-slide 0.5s linear;
}

/* new */
::view-transition-new(content-transition) {
  animation: content-slide 0.5s linear reverse;
}

/* keyframes */
@keyframes content-slide {
  0% {
    transform: scale(1);
  }
  15% {
    transform: translateY(0);
  }
  85% {
    transform: translateY(100%);
    opacity: 0;
  }
  100% {
    opacity: 0;
    transform: translateY(100%) scale(1);
  }
}

CONTENT

⏪ Recap - View Transitions

  • Trigering a View Transition
  • The Default Transition
  • Customizing a Transitions

Animation Optimization ⚡

  • Size changes are costly
  • Some properties are GPU accelearated
    • transform
    • filter
    • opacity
  • Using will-change
    • Last resort
    • Do not apply to too many elements

Premature optimization? It's relatively easy to write it correctly first time

🔮 Will-Change

  • Used to inform the browser that certain elements of a property will be changed
  • The browser can use this to optimize the transition/animation of the property
.greeting {
  will-change: transform;
}

The 12 Principles of Animation 📔

  • Introduced in "The Illusion of Life" by Frank Thomas and Ollie Johnston

What do we do with our new found skills?

1. Squash and Stretch 🪢

Illusion of weight and volume

web-animations/principles-1.css
.greeting {
  display: inline-block;
  text-transform: lowercase;
  padding: 0.5rem 1rem;
  background-color: var(--color-brand-muted);
  cursor:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
      16 0,
    auto;

  color: transparent;
  margin-top: 200px;
  aspect-ratio: 1;
}

.wrapper {
  padding: 0px 100px;
}

.greeting {
  --duration-s: calc(var(--duration, 1) * 1s);

  --timing-up: cubic-bezier(0.33333, 0.66667, 0.66667, 1);
  --timing-down: cubic-bezier(0.33333, 0, 0.66667, 0.33333);

  display: inline-block;
  animation-iteration-count: infinite;
  animation-duration: var(--duration-s);

  animation-direction: alternate;
  animation-name: greeting-1-move, greeting-1-squash;
  animation-timing-function: var(--timing-up);
  animation-composition: accumulate;

  will-change: transform;
}

@keyframes greeting-1-move {
  0% {
    transform: translateY(0px);
  }

  100% {
    transform: translateY(-200px);
  }
}

@keyframes greeting-1-squash {
  0% {
    transform: scaleY(0.5) scaleX(1.5);
  }

  20% {
    transform: scaleY(1.5) scaleX(0.5);
  }

  95% {
    transform: scaleY(1) scaleX(1);
  }

  100% {
    transform: scaleY(1) scaleX(1);
  }
}
Hi there 👋

2. Anticipation ⌛

Using small actions to indicate an action is about to happen

web-animations/principles-2.css
.greeting {
  display: inline-block;
  text-transform: lowercase;
  padding: 0.5rem 1rem;
  background-color: var(--color-brand-muted);
  cursor:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
      16 0,
    auto;

  color: transparent;
  aspect-ratio: 1;
}

.wrapper {
  padding: 0px 100px;
}

.greeting {
  --duration-s: calc(var(--duration, 1) * 1s);

  display: inline-block;
  transition-property: transform;
  transition-duration: var(--duration-s);
  transition-timing-function: cubic-bezier(0.75, -0.61, 0.87, -0.16);
}

.wrapper:hover .greeting {
  transform: translateX(20vw);
}
Hi there 👋

3. Follow Through and Overlap 🐾

Adding movement after an action

web-animations/principles-3.css
.greeting {
  display: inline-block;
  text-transform: lowercase;
  padding: 0.5rem 1rem;
  background-color: var(--color-brand-muted);
  color: var(--color-on-base);
  cursor:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
      16 0,
    auto;
}

.hand {
  display: inline-block;
}

.greeting {
  --duration-s: calc(var(--duration, 1) * 1s);

  transition-property: all;
  transition-duration: var(--duration-s);
  transition-timing-function: ease-in-out;
}

.greeting:hover {
  background-color: var(--color-brand);
  color: var(--color-on-brand);
  animation-name: greeting-3;
  animation-duration: var(--duration-s);
  animation-delay: var(--duration-s);
}

@keyframes greeting-3 {
  0% {
    scale: 1;
  }

  50% {
    scale: 1.1;
  }

  100% {
    scale: 1;
  }
}
Hi there 👋

4. Arcs ⭕

Nature moves in arcs

web-animations/principles-4.css
.greeting {
  display: inline-block;
  text-transform: lowercase;
  padding: 0.5rem 1rem;
  background-color: var(--color-brand-muted);
  color: var(--color-on-base);
  cursor:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
      16 0,
    auto;
}

.hand {
  --duration-s: calc(var(--duration, 1) * 1s);

  display: inline-block;
  animation-duration: var(--duration-s);
  animation-iteration-count: infinite;
  animation-name: hand-wave-multi;
  animation-play-state: paused;
  transform-origin: 50px 50px;
}

.greeting:hover .hand {
  animation-play-state: running;
}

@keyframes hand-wave-multi {
  0% {
    transform: rotate(0deg);
  }

  15% {
    scale: 150%;
    rotate: 0deg;
    translate: 0px -8px;
  }

  50% {
    scale: 150%;
    rotate: 30deg;
    translate: 0px -8px;
  }

  85% {
    scale: 150%;
    rotate: 0deg;
    translate: 0px -8px;
  }

  100% {
    rotate: 0deg;
  }
}
Hi there 👋

5. Slow In & Slow Out 🦥

Easing in and out of an action

web-animations/principles-5.css
.greeting {
  display: inline-block;
  text-transform: lowercase;
  padding: 0.5rem 1rem;
  background-color: var(--color-brand-muted);
  color: var(--color-on-base);
  cursor:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
      16 0,
    auto;
}

.hand {
  display: inline-block;
}

.greeting {
  --duration-s: calc(var(--duration, 1) * 1s);

  transition-property: all;
  transition-duration: var(--duration-s);
  transition-timing-function: ease-in-out;
}

.greeting:hover {
  transform: scale(1.1);
  background-color: var(--color-brand);
  color: var(--color-on-brand);
}
Hi there 👋

6. Timing ⌚

Number of frames for a given action

web-animations/principles-6.css
.greeting {
  display: inline-block;
  text-transform: lowercase;
  padding: 0.5rem 1rem;
  background-color: var(--color-brand-muted);
  cursor:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
      16 0,
    auto;

  color: transparent;
  margin-top: 200px;
  aspect-ratio: 1;
}

.wrapper {
  padding: 0px 100px;
}

.greeting {
  --duration-s: calc(var(--duration, 1) * 1s);

  display: inline-block;
  animation-iteration-count: infinite;
  animation-duration: var(--duration-s);

  animation-direction: alternate;
  animation-name: greeting-1-move, greeting-1-squash;
  animation-timing-function: steps(var(--steps, 3), jump-both);
  animation-composition: accumulate;

  will-change: transform;
}

@keyframes greeting-1-move {
  0% {
    transform: translateY(0px);
  }

  100% {
    transform: translateY(-200px);
  }
}

@keyframes greeting-1-squash {
  0% {
    transform: scaleY(0.5) scaleX(1.5);
  }

  20% {
    transform: scaleY(1.5) scaleX(0.5);
  }

  95% {
    transform: scaleY(1) scaleX(1);
  }

  100% {
    transform: scaleY(1) scaleX(1);
  }
}
Hi there 👋

7. Secondary Action 🔂

Additional actions that enhance an action

web-animations/principles-7.css
.greeting {
  display: inline-block;
  text-transform: lowercase;
  padding: 0.5rem 1rem;
  background-color: var(--color-brand-muted);
  color: var(--color-on-base);
  cursor:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
      16 0,
    auto;
}

.greeting {
  --duration-s: calc(var(--duration, 1) * 1s);
}

.hand {
  display: inline-block;
  transform-origin: bottom right;
}

.greeting:hover {
  background-color: var(--color-brand);
  transition: background-color var(--duration-s);
}

.hand {
  animation-delay: calc(0.5 * var(--duration-s));
  animation-duration: var(--duration-s);
}

.greeting:hover .hand {
  animation-name: hand-wave-multi;
}

@keyframes hand-wave-multi {
  0% {
    transform: rotate(0deg);
  }

  15% {
    scale: 150%;
    transform: rotate(0deg);
    translate: 0px -8px;
  }

  50% {
    scale: 150%;
    transform: rotate(30deg);
    translate: 0px -8px;
  }

  85% {
    scale: 150%;
    transform: rotate(0deg);
    translate: 0px -8px;
  }

  100% {
    transform: rotate(0deg);
  }
}
Hi there 👋

8. Exaggeration 💥

Provide dramatic effect

web-animations/principles-8.css
.greeting {
  display: inline-block;
  text-transform: lowercase;
  padding: 0.5rem 1rem;
  background-color: var(--color-brand-muted);
  color: var(--color-on-base);
  cursor:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
      16 0,
    auto;
}

.greeting {
  --duration-s: calc(var(--duration, 1) * 1s);
  --scale-p: calc(var(--scale, 1) * 1%);
}

.hand {
  display: inline-block;
  transform-origin: bottom right;
}

.greeting:hover {
  background-color: var(--color-brand);
  transition: background-color var(--duration-s);
}

.hand {
  animation-delay: calc(0.5 * var(--duration-s));
  animation-duration: var(--duration-s);
}

.greeting:hover .hand {
  animation-name: hand-wave-multi;
}

@keyframes hand-wave-multi {
  0% {
    transform: rotate(0deg);
  }

  15% {
    scale: var(--scale-p);
    transform: rotate(0deg);
    translate: 0px -8px;
  }

  50% {
    scale: var(--scale-p);
    transform: rotate(30deg);
    translate: 0px -8px;
  }

  85% {
    scale: var(--scale-p);
    transform: rotate(0deg);
    translate: 0px -8px;
  }

  100% {
    transform: rotate(0deg);
  }
}
Hi there 👋

9. Staging 🎭

Direct the audience attention

web-animations/principles-9.css
.greeting {
  display: inline-block;
  text-transform: lowercase;
  padding: 0.5rem 1rem;
  background-color: var(--color-brand-muted);
  color: var(--color-on-base);
  cursor:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
      16 0,
    auto;
}

.hand {
  display: inline-block;
}

.greeting {
  --duration-s: calc(var(--duration, 1) * 1s);

  transition-property: all;
  transition-duration: var(--duration-s);
  transition-timing-function: ease-in-out;

  animation-name: greeting-9;
  animation-duration: var(--duration-s);
  animation-direction: alternate;
  animation-iteration-count: infinite;
}

.greeting:hover {
  background-color: var(--color-brand);
  color: var(--color-on-brand);
}

@keyframes greeting-9 {
  from {
    border: solid 4px transparent;
  }

  to {
    border: solid 4px var(--color-brand);
  }
}
Hi there 👋

10. Straight Ahead & Pose to Pose 📼

Two different techniques for determining frames

  • Straight ahead - Draw frames consecutively
  • Post to Pose - Draw frames at start and end the figure out what's in between
11. Solid Drawings 🖼️

Make it feel like 2D shapes occupy a 3D space

web-animations/principles-11.css
.greeting {
  display: inline-block;
  text-transform: lowercase;
  padding: 0.5rem 1rem;
  background-color: var(--color-brand-muted);
  color: var(--color-on-base);
  cursor:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
      16 0,
    auto;
}

.greeting {
  --duration-s: calc(var(--duration, 1) * 1s);
  --scale-p: calc(var(--scale, 1) * 1%);
  --perspective-px: calc(var(--perspective, 1) * 1px);
  --rotate-x-deg: calc(var(--rotate-x, 1) * 1deg);
  --rotate-y-deg: calc(var(--rotate-y, 1) * 1deg);
  --rotate-z-deg: calc(var(--rotate-z, 1) * 1deg);

  margin-top: 20px;
  transition: all var(--duration-s);
}

.hand {
  display: inline-block;
  transform-origin: bottom right;
}

.greeting:hover {
  background-color: var(--color-brand);
  transform: perspective(var(--perspective-px)) rotateX(var(--rotate-x-deg))
    rotateY(var(--rotate-y-deg)) rotateZ(var(--rotate-z-deg));
}

.hand {
  animation-delay: calc(0.5 * var(--duration-s));
  animation-duration: var(--duration-s);
}

.greeting:hover .hand {
  animation-name: hand-wave-multi;
}

@keyframes hand-wave-multi {
  0% {
    transform: rotate(0deg);
  }

  15% {
    scale: var(--scale-p);
    transform: rotate(0deg);
    translate: 0px -8px;
  }

  50% {
    scale: var(--scale-p);
    transform: rotate(30deg);
    translate: 0px -8px;
  }

  85% {
    scale: var(--scale-p);
    transform: rotate(0deg);
    translate: 0px -8px;
  }

  100% {
    transform: rotate(0deg);
  }
}
Hi there 👋

12. Appeal 🌟
  • Simple
  • Clear
  • Compelling

Make the viewer feel something

⏪ Recap - Principles of Animation

  1. Squash and Stretch
  2. Anticipation
  3. Follow Through and Overlap
  4. Arcs
  5. Slow In & Slow Out
  6. Timing
  7. Secondary Action
  8. Exaggeration
  9. Staging
  10. Straight Ahead & Pose to Pose
  11. Solid Drawings
  12. Appeal

🪟 Frameworks and Libraries 📚

For defining animations, not design systems

When not to use Animations 🚫

  • If the the user has enabled reduced-motion
  • If it will add too much visual noise
  • If they will distract the user
  • Responsiveness and accessibility concerns

Suggestions 💡

  • Use animations lightly
  • Less is more, small interactions go a long way
  • Define your identity and use animations to enhance that
  • Understanding interactivity on different screen types
  • Animations should have a purpose

Case Study 🕵️

Josh Comeau

  • Changing themes
  • Navigation dropdown
  • Background svg
  • Link hover
  • Twitter link

Ling's Cars

  • Sense of identity
  • Maximalism can work too

References and Further Reading 📖

MDN

Principles of Animation

StackOverflow