Introduction to Animation on the Web

20 May 2024

Updated: 20 May 2024

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 🌐

Nabeel Valley 🤓

  • From Pretoria
  • Currently in NL
  • Full Stack Developer
  • @ Entelect since July 2023
  • On the Digital Platform team at Rabobank
  • Like making things
Nabeel Valley

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
1
.my-stuff {
2
/* def */
3
--my-color: red;
4
--my-size: 12px;
5
6
/* use */
7
background-color: var(--my-color);
8
9
/* default */
10
height: var(--my-size, 24px);
11
width: var(--some-undefined-value, 24px);
12
}

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/index.html
1
<div class="wrapper">
2
<div class="greeting">
3
Hi there
4
<span class="hand">👋</span>
5
</div>
6
</div>
web-animations/styles.css
1
.greeting {
2
display: inline-block;
3
text-transform: lowercase;
4
padding: 0.5rem 1rem;
5
background-color: var(--color-brand-muted);
6
color: var(--color-on-base);
7
cursor:
8
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
9
16 0,
10
auto;
11
}
12
13
.hand {
14
display: inline-block;
15
}

Using Transitions 👷

Questions?

web-animations/transition-simple.css
15 collapsed lines
1
.greeting {
2
display: inline-block;
3
text-transform: lowercase;
4
padding: 0.5rem 1rem;
5
background-color: var(--color-brand-muted);
6
color: var(--color-on-base);
7
cursor:
8
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
9
16 0,
10
auto;
11
}
12
13
.hand {
14
display: inline-block;
15
}
16
17
.greeting {
18
transition-property: all;
19
transition-duration: 300ms;
20
transition-delay: 100ms;
21
transition-timing-function: ease-in;
22
}
23
24
.greeting:hover {
25
transform: scale(1.1);
26
background-color: var(--color-brand);
27
color: var(--color-on-brand);
28
}

📏 Shorthand Syntax

web-animations/transition-simple-alt.css
16 collapsed lines
1
.greeting {
2
display: inline-block;
3
text-transform: lowercase;
4
padding: 0.5rem 1rem;
5
background-color: var(--color-brand-muted);
6
color: var(--color-on-base);
7
cursor:
8
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
9
16 0,
10
auto;
11
}
12
13
.hand {
14
display: inline-block;
15
}
16
17
.greeting {
18
/* shorthand */
19
transition: all 300ms 100ms ease-in;
20
}
6 collapsed lines
21
22
.greeting:hover {
23
transform: scale(1.1);
24
background-color: var(--color-brand);
25
color: var(--color-on-brand);
26
}

Multi Property Transitions ♾️

web-animations/transition-properties.css
16 collapsed lines
1
.greeting {
2
display: inline-block;
3
text-transform: lowercase;
4
padding: 0.5rem 1rem;
5
background-color: var(--color-brand-muted);
6
color: var(--color-on-base);
7
cursor:
8
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
9
16 0,
10
auto;
11
}
12
13
.hand {
14
display: inline-block;
15
}
16
17
.greeting {
18
transition-property: transform, color, background-color;
19
transition-duration: 300ms, 100ms, 100ms;
20
transition-delay: 0ms, 300ms, 300ms;
21
transition-timing-function: ease-in, ease-out, ease-in-out;
22
}
6 collapsed lines
23
24
.greeting:hover {
25
transform: scale(1.1);
26
background-color: var(--color-brand);
27
color: var(--color-on-brand);
28
}

🤏 Multi Property Transition Shorthand

web-animations/transition-properties-alt.css
16 collapsed lines
1
.greeting {
2
display: inline-block;
3
text-transform: lowercase;
4
padding: 0.5rem 1rem;
5
background-color: var(--color-brand-muted);
6
color: var(--color-on-base);
7
cursor:
8
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
9
16 0,
10
auto;
11
}
12
13
.hand {
14
display: inline-block;
15
}
16
17
.greeting {
18
transition:
19
transform 300ms 0ms ease-in,
20
color 100ms 300ms ease-out,
21
background-color 100ms 300ms ease-in-out;
22
}
6 collapsed lines
23
24
.greeting:hover {
25
transform: scale(1.1);
26
background-color: var(--color-brand);
27
color: var(--color-on-brand);
28
}

Combining Transitions 🤝

web-animations/transition-hand.css
29 collapsed lines
1
.greeting {
2
display: inline-block;
3
text-transform: lowercase;
4
padding: 0.5rem 1rem;
5
background-color: var(--color-brand-muted);
6
color: var(--color-on-base);
7
cursor:
8
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
9
16 0,
10
auto;
11
}
12
13
.hand {
14
display: inline-block;
15
}
16
17
.greeting {
18
transition:
19
transform 300ms 0ms ease-in,
20
color 100ms 300ms ease-out,
21
background-color 100ms 300ms ease-in-out;
22
}
23
24
.greeting:hover {
25
transform: scale(1.1);
26
background-color: var(--color-brand);
27
color: var(--color-on-brand);
28
}
29
30
.greeting .hand {
31
transition: transform 100ms 0ms ease-out;
32
transform-origin: bottom right;
33
}
34
35
.greeting:hover .hand {
36
transition-duration: 300ms;
37
transition-delay: 400ms;
38
transform: rotate(30deg);
39
}

Timing ⏱️ Functions

web-animations/transition-timing.css
16 collapsed lines
1
.greeting {
2
display: inline-block;
3
text-transform: lowercase;
4
padding: 0.5rem 1rem;
5
background-color: var(--color-brand-muted);
6
color: var(--color-on-base);
7
cursor:
8
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
9
16 0,
10
auto;
11
}
12
13
.hand {
14
display: inline-block;
15
}
16
17
.greeting {
18
transition-property: color, transform;
19
transition-duration: 1s;
20
transition-timing-function: var(--timing-function);
21
}
22
23
.greeting:hover {
24
transform: scale(1.2);
25
background-color: var(--color-brand);
26
color: var(--color-on-brand);
27
}

⏪ 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
12 collapsed lines
1
.greeting {
2
display: inline-block;
3
text-transform: lowercase;
4
padding: 0.5rem 1rem;
5
background-color: var(--color-brand-muted);
6
color: var(--color-on-base);
7
cursor:
8
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
9
16 0,
10
auto;
11
}
12
13
.hand {
14
display: inline-block;
15
transform-origin: bottom right;
16
17
/* basic properties */
18
animation-delay: 100ms;
19
animation-duration: 500ms;
20
animation-timing-function: ease-in-out;
21
22
/* keyframes name */
23
animation-name: hand-wave;
24
25
/* iterations */
26
animation-iteration-count: infinite;
27
28
/* direction */
29
animation-direction: alternate;
30
31
/* completion state */
32
animation-fill-mode: forwards;
33
}
34
35
@keyframes hand-wave {
36
from {
37
transform: rotate(0deg);
38
}
39
40
to {
41
transform: rotate(30deg);
42
}
43
}

State Based Animations 🔛

web-animations/animation-hover.css
12 collapsed lines
1
.greeting {
2
display: inline-block;
3
text-transform: lowercase;
4
padding: 0.5rem 1rem;
5
background-color: var(--color-brand-muted);
6
color: var(--color-on-base);
7
cursor:
8
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
9
16 0,
10
auto;
11
}
12
13
.hand {
14
display: inline-block;
15
transform-origin: bottom right;
16
17
animation-delay: 100ms;
18
animation-duration: 500ms;
19
animation-timing-function: ease-in-out;
20
animation-name: hand-wave;
21
animation-iteration-count: infinite;
22
animation-direction: alternate;
23
animation-fill-mode: both;
24
25
/* state */
26
animation-play-state: paused;
27
}
28
29
/* hover */
30
.greeting:hover .hand {
31
/* state */
32
animation-play-state: running;
33
}
34
35
@keyframes hand-wave {
36
from {
37
transform: rotate(0deg);
38
}
39
40
to {
41
transform: rotate(30deg);
42
}
43
}

Multi Property Animations 🍿

web-animations/animation-properties.css
12 collapsed lines
1
.greeting {
2
display: inline-block;
3
text-transform: lowercase;
4
padding: 0.5rem 1rem;
5
background-color: var(--color-brand-muted);
6
color: var(--color-on-base);
7
cursor:
8
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
9
16 0,
10
auto;
11
}
12
13
.hand {
7 collapsed lines
14
display: inline-block;
15
transform-origin: bottom right;
16
17
/* basic properties */
18
animation-duration: 1s;
19
animation-iteration-count: infinite;
20
21
/* multi */
22
animation-name: hand-wave-multi;
23
animation-play-state: paused;
24
}
25
26
.greeting:hover .hand {
27
animation-play-state: running;
28
}
29
30
@keyframes hand-wave-multi {
31
0% {
32
transform: rotate(0deg);
33
}
34
35
15% {
36
scale: 150%;
37
transform: rotate(0deg);
38
translate: 0px -8px;
39
}
40
41
50% {
42
scale: 150%;
43
transform: rotate(30deg);
44
translate: 0px -8px;
45
}
46
47
85% {
48
scale: 150%;
49
transform: rotate(0deg);
50
translate: 0px -8px;
51
}
52
53
100% {
54
transform: rotate(0deg);
55
}
56
}

⏪ 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
18 collapsed lines
1
<script>
2
const words = [
3
"pale",
4
"dangerous",
5
"secret",
6
"madly",
7
"sharp",
8
"mammoth",
9
"overrated",
10
"painful",
11
"ill-informed",
12
"dizzy",
13
"ambitious",
14
"stable"
15
]
16
17
const random = () => words[Math.floor(Math.random()*words.length)].toUpperCase();
18
19
const handleWrapperClicked = (wrapper) => () => {
20
// updateCallback
21
document.startViewTransition(() => {
22
const content = wrapper.querySelector('.view-transitions-content')
23
24
content.classList.toggle('inverted')
25
content.innerHTML = random()
26
})
27
}
28
29
// wait for all snippets to initialize
30
setTimeout(() => {
31
const wrappers = document.querySelectorAll('.view-transitions-wrapper')
32
for (const wrapper of wrappers) {
33
// trigger
34
wrapper.addEventListener('click', handleWrapperClicked(wrapper))
35
}
36
}, 1000)
37
</script>
17 collapsed lines
38
39
<style is:global>
40
.view-transitions-wrapper {
41
overflow: hidden;
42
}
43
44
.view-transitions-content {
45
padding: 1rem;
46
background-color: var(--color-brand);
47
user-select: none;
48
margin: 0;
49
50
&.inverted {
51
filter: invert();
52
}
53
}
54
</style>

The Default Transition 😐

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

CONTENT

Understanding the Transition 🤔

Questions?

web-animations/view-transitions-slide.css
1
/* assign */
2
.view-transitions-content {
3
view-transition-name: content-transition;
4
}
5
6
/* old */
7
::view-transition-old(content-transition) {
8
animation: content-slide 0.5s linear;
9
}
10
11
/* new */
12
::view-transition-new(content-transition) {
13
animation: content-slide 0.5s linear reverse;
14
}
15
16
/* keyframes */
17
@keyframes content-slide {
18
0% {
19
transform: scale(1);
20
}
21
15% {
22
transform: translateY(0);
23
}
24
85% {
25
transform: translateY(100%);
26
opacity: 0;
27
}
28
100% {
29
opacity: 0;
30
transform: translateY(100%) scale(1);
31
}
32
}

⏪ 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
1
.greeting {
2
will-change: transform;
3
}

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
37 collapsed lines
1
.greeting {
2
display: inline-block;
3
text-transform: lowercase;
4
padding: 0.5rem 1rem;
5
background-color: var(--color-brand-muted);
6
cursor:
7
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
8
16 0,
9
auto;
10
11
color: transparent;
12
margin-top: 200px;
13
aspect-ratio: 1;
14
}
15
16
.wrapper {
17
padding: 0px 100px;
18
}
19
20
.greeting {
21
--duration-s: calc(var(--duration, 1) * 1s);
22
23
--timing-up: cubic-bezier(0.33333, 0.66667, 0.66667, 1);
24
--timing-down: cubic-bezier(0.33333, 0, 0.66667, 0.33333);
25
26
display: inline-block;
27
animation-iteration-count: infinite;
28
animation-duration: var(--duration-s);
29
30
animation-direction: alternate;
31
animation-name: greeting-1-move, greeting-1-squash;
32
animation-timing-function: var(--timing-up);
33
animation-composition: accumulate;
34
35
will-change: transform;
36
}
37
38
@keyframes greeting-1-move {
39
0% {
40
transform: translateY(0px);
41
}
42
43
100% {
44
transform: translateY(-200px);
45
}
46
}
47
48
@keyframes greeting-1-squash {
49
0% {
50
transform: scaleY(0.5) scaleX(1.5);
51
}
52
53
20% {
54
transform: scaleY(1.5) scaleX(0.5);
55
}
56
57
95% {
58
transform: scaleY(1) scaleX(1);
59
}
60
61
100% {
62
transform: scaleY(1) scaleX(1);
63
}
64
}

2. Anticipation ⌛

Using small actions to indicate an action is about to happen

web-animations/principles-2.css
18 collapsed lines
1
.greeting {
2
display: inline-block;
3
text-transform: lowercase;
4
padding: 0.5rem 1rem;
5
background-color: var(--color-brand-muted);
6
cursor:
7
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
8
16 0,
9
auto;
10
11
color: transparent;
12
aspect-ratio: 1;
13
}
14
15
.wrapper {
16
padding: 0px 100px;
17
}
18
19
.greeting {
20
--duration-s: calc(var(--duration, 1) * 1s);
21
22
display: inline-block;
23
transition-property: transform;
24
transition-duration: var(--duration-s);
25
transition-timing-function: cubic-bezier(0.75, -0.61, 0.87, -0.16);
26
}
27
28
.wrapper:hover .greeting {
29
transform: translateX(20vw);
30
}

3. Follow Through and Overlap 🐾

Adding movement after an action

web-animations/principles-3.css
16 collapsed lines
1
.greeting {
2
display: inline-block;
3
text-transform: lowercase;
4
padding: 0.5rem 1rem;
5
background-color: var(--color-brand-muted);
6
color: var(--color-on-base);
7
cursor:
8
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
9
16 0,
10
auto;
11
}
12
13
.hand {
14
display: inline-block;
15
}
16
17
.greeting {
18
--duration-s: calc(var(--duration, 1) * 1s);
19
20
transition-property: all;
21
transition-duration: var(--duration-s);
22
transition-timing-function: ease-in-out;
23
}
24
25
.greeting:hover {
26
background-color: var(--color-brand);
27
color: var(--color-on-brand);
28
animation-name: greeting-3;
29
animation-duration: var(--duration-s);
30
animation-delay: var(--duration-s);
31
}
32
33
@keyframes greeting-3 {
34
0% {
35
scale: 1;
36
}
37
38
50% {
39
scale: 1.1;
40
}
41
42
100% {
43
scale: 1;
44
}
45
}

4. Arcs ⭕

Nature moves in arcs

web-animations/principles-4.css
12 collapsed lines
1
.greeting {
2
display: inline-block;
3
text-transform: lowercase;
4
padding: 0.5rem 1rem;
5
background-color: var(--color-brand-muted);
6
color: var(--color-on-base);
7
cursor:
8
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
9
16 0,
10
auto;
11
}
12
13
.hand {
14
--duration-s: calc(var(--duration, 1) * 1s);
15
16
display: inline-block;
17
animation-duration: var(--duration-s);
18
animation-iteration-count: infinite;
19
animation-name: hand-wave-multi;
20
animation-play-state: paused;
21
transform-origin: 50px 50px;
22
}
23
24
.greeting:hover .hand {
25
animation-play-state: running;
26
}
27
28
@keyframes hand-wave-multi {
29
0% {
30
transform: rotate(0deg);
31
}
32
33
15% {
34
scale: 150%;
35
rotate: 0deg;
36
translate: 0px -8px;
37
}
38
39
50% {
40
scale: 150%;
41
rotate: 30deg;
42
translate: 0px -8px;
43
}
44
45
85% {
46
scale: 150%;
47
rotate: 0deg;
48
translate: 0px -8px;
49
}
50
51
100% {
52
rotate: 0deg;
53
}
54
}

5. Slow In & Slow Out 🦥

Easing in and out of an action

web-animations/principles-5.css
12 collapsed lines
1
.greeting {
2
display: inline-block;
3
text-transform: lowercase;
4
padding: 0.5rem 1rem;
5
background-color: var(--color-brand-muted);
6
color: var(--color-on-base);
7
cursor:
8
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
9
16 0,
10
auto;
11
}
12
13
.hand {
14
display: inline-block;
15
}
16
17
.greeting {
18
--duration-s: calc(var(--duration, 1) * 1s);
19
20
transition-property: all;
21
transition-duration: var(--duration-s);
22
transition-timing-function: ease-in-out;
23
}
24
25
.greeting:hover {
26
transform: scale(1.1);
27
background-color: var(--color-brand);
28
color: var(--color-on-brand);
29
}

6. Timing ⌚

Number of frames for a given action

web-animations/principles-6.css
19 collapsed lines
1
.greeting {
2
display: inline-block;
3
text-transform: lowercase;
4
padding: 0.5rem 1rem;
5
background-color: var(--color-brand-muted);
6
cursor:
7
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
8
16 0,
9
auto;
10
11
color: transparent;
12
margin-top: 200px;
13
aspect-ratio: 1;
14
}
15
16
.wrapper {
17
padding: 0px 100px;
18
}
19
20
.greeting {
21
--duration-s: calc(var(--duration, 1) * 1s);
22
23
display: inline-block;
24
animation-iteration-count: infinite;
25
animation-duration: var(--duration-s);
26
27
animation-direction: alternate;
28
animation-name: greeting-1-move, greeting-1-squash;
29
animation-timing-function: steps(var(--steps, 3), jump-both);
30
animation-composition: accumulate;
31
32
will-change: transform;
33
}
28 collapsed lines
34
35
@keyframes greeting-1-move {
36
0% {
37
transform: translateY(0px);
38
}
39
40
100% {
41
transform: translateY(-200px);
42
}
43
}
44
45
@keyframes greeting-1-squash {
46
0% {
47
transform: scaleY(0.5) scaleX(1.5);
48
}
49
50
20% {
51
transform: scaleY(1.5) scaleX(0.5);
52
}
53
54
95% {
55
transform: scaleY(1) scaleX(1);
56
}
57
58
100% {
59
transform: scaleY(1) scaleX(1);
60
}
61
}

7. Secondary Action 🔂

Additional actions that enhance an action

web-animations/principles-7.css
21 collapsed lines
1
.greeting {
2
display: inline-block;
3
text-transform: lowercase;
4
padding: 0.5rem 1rem;
5
background-color: var(--color-brand-muted);
6
color: var(--color-on-base);
7
cursor:
8
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
9
16 0,
10
auto;
11
}
12
13
.greeting {
14
--duration-s: calc(var(--duration, 1) * 1s);
15
}
16
17
.hand {
18
display: inline-block;
19
transform-origin: bottom right;
20
}
21
22
.greeting:hover {
23
background-color: var(--color-brand);
24
transition: background-color var(--duration-s);
25
}
26
27
.hand {
28
animation-delay: calc(0.5 * var(--duration-s));
29
animation-duration: var(--duration-s);
30
}
31
32
.greeting:hover .hand {
33
animation-name: hand-wave-multi;
34
}
28 collapsed lines
35
36
@keyframes hand-wave-multi {
37
0% {
38
transform: rotate(0deg);
39
}
40
41
15% {
42
scale: 150%;
43
transform: rotate(0deg);
44
translate: 0px -8px;
45
}
46
47
50% {
48
scale: 150%;
49
transform: rotate(30deg);
50
translate: 0px -8px;
51
}
52
53
85% {
54
scale: 150%;
55
transform: rotate(0deg);
56
translate: 0px -8px;
57
}
58
59
100% {
60
transform: rotate(0deg);
61
}
62
}

8. Exaggeration 💥

Provide dramatic effect

web-animations/principles-8.css
36 collapsed lines
1
.greeting {
2
display: inline-block;
3
text-transform: lowercase;
4
padding: 0.5rem 1rem;
5
background-color: var(--color-brand-muted);
6
color: var(--color-on-base);
7
cursor:
8
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
9
16 0,
10
auto;
11
}
12
13
.greeting {
14
--duration-s: calc(var(--duration, 1) * 1s);
15
--scale-p: calc(var(--scale, 1) * 1%);
16
}
17
18
.hand {
19
display: inline-block;
20
transform-origin: bottom right;
21
}
22
23
.greeting:hover {
24
background-color: var(--color-brand);
25
transition: background-color var(--duration-s);
26
}
27
28
.hand {
29
animation-delay: calc(0.5 * var(--duration-s));
30
animation-duration: var(--duration-s);
31
}
32
33
.greeting:hover .hand {
34
animation-name: hand-wave-multi;
35
}
36
37
@keyframes hand-wave-multi {
38
0% {
39
transform: rotate(0deg);
40
}
41
42
15% {
43
scale: var(--scale-p);
44
transform: rotate(0deg);
45
translate: 0px -8px;
46
}
47
48
50% {
49
scale: var(--scale-p);
50
transform: rotate(30deg);
51
translate: 0px -8px;
52
}
53
54
85% {
55
scale: var(--scale-p);
56
transform: rotate(0deg);
57
translate: 0px -8px;
58
}
59
60
100% {
61
transform: rotate(0deg);
62
}
63
}

9. Staging 🎭

Direct the audience attention

web-animations/principles-9.css
34 collapsed lines
1
.greeting {
2
display: inline-block;
3
text-transform: lowercase;
4
padding: 0.5rem 1rem;
5
background-color: var(--color-brand-muted);
6
color: var(--color-on-base);
7
cursor:
8
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
9
16 0,
10
auto;
11
}
12
13
.hand {
14
display: inline-block;
15
}
16
17
.greeting {
18
--duration-s: calc(var(--duration, 1) * 1s);
19
20
transition-property: all;
21
transition-duration: var(--duration-s);
22
transition-timing-function: ease-in-out;
23
24
animation-name: greeting-9;
25
animation-duration: var(--duration-s);
26
animation-direction: alternate;
27
animation-iteration-count: infinite;
28
}
29
30
.greeting:hover {
31
background-color: var(--color-brand);
32
color: var(--color-on-brand);
33
}
34
35
@keyframes greeting-9 {
36
from {
37
border: solid 4px transparent;
38
}
39
40
to {
41
border: solid 4px var(--color-brand);
42
}
43
}

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
29 collapsed lines
1
.greeting {
2
display: inline-block;
3
text-transform: lowercase;
4
padding: 0.5rem 1rem;
5
background-color: var(--color-brand-muted);
6
color: var(--color-on-base);
7
cursor:
8
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' style='font-size:24px;'><text y='50%'>🤚</text></svg>")
9
16 0,
10
auto;
11
}
12
13
.greeting {
14
--duration-s: calc(var(--duration, 1) * 1s);
15
--scale-p: calc(var(--scale, 1) * 1%);
16
--perspective-px: calc(var(--perspective, 1) * 1px);
17
--rotate-x-deg: calc(var(--rotate-x, 1) * 1deg);
18
--rotate-y-deg: calc(var(--rotate-y, 1) * 1deg);
19
--rotate-z-deg: calc(var(--rotate-z, 1) * 1deg);
20
21
margin-top: 20px;
22
transition: all var(--duration-s);
23
}
24
25
.hand {
26
display: inline-block;
27
transform-origin: bottom right;
28
}
29
30
.greeting:hover {
31
background-color: var(--color-brand);
32
transform: perspective(var(--perspective-px)) rotateX(var(--rotate-x-deg))
33
rotateY(var(--rotate-y-deg)) rotateZ(var(--rotate-z-deg));
34
}
37 collapsed lines
35
36
.hand {
37
animation-delay: calc(0.5 * var(--duration-s));
38
animation-duration: var(--duration-s);
39
}
40
41
.greeting:hover .hand {
42
animation-name: hand-wave-multi;
43
}
44
45
@keyframes hand-wave-multi {
46
0% {
47
transform: rotate(0deg);
48
}
49
50
15% {
51
scale: var(--scale-p);
52
transform: rotate(0deg);
53
translate: 0px -8px;
54
}
55
56
50% {
57
scale: var(--scale-p);
58
transform: rotate(30deg);
59
translate: 0px -8px;
60
}
61
62
85% {
63
scale: var(--scale-p);
64
transform: rotate(0deg);
65
translate: 0px -8px;
66
}
67
68
100% {
69
transform: rotate(0deg);
70
}
71
}

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