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
- nabeelvalley.co.za
- @not_nabeel
- @nabeelvalley
![Nabeel Valley](/content/profile.jpg)
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
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
1<div class="wrapper">2 <div class="greeting">3 Hi there4 <span class="hand">👋</span>5 </div>6</div>
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?
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
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 ♾️
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
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 🤝
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
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?
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 🔛
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 🍿
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?
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 // updateCallback21 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 initialize30 setTimeout(() => {31 const wrappers = document.querySelectorAll('.view-transitions-wrapper')32 for (const wrapper of wrappers) {33 // trigger34 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
1<div class="view-transitions-wrapper">2 <h1 class="view-transitions-content">CONTENT</h1>3</div>
CONTENT
Understanding the Transition 🤔
Questions?
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}
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
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
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
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
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
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
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
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
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
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
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
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
- Squash and Stretch
- Anticipation
- Follow Through and Overlap
- Arcs
- Slow In & Slow Out
- Timing
- Secondary Action
- Exaggeration
- Staging
- Straight Ahead & Pose to Pose
- Solid Drawings
- Appeal
🪟 Frameworks and Libraries 📚
- TailwindCSS Animation Properties - Primitives for building animations
- Animate.css - Predefined animations and transitions
- Frame Motion - More sophisticated Javascript driven animations
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 🕵️
- Changing themes
- Navigation dropdown
- Background svg
- Link hover
- Twitter link
- Sense of identity
- Maximalism can work too
References and Further Reading 📖
MDN
Principles of Animation
- The Illusion of Life - The 12 Principles
- 12 Principles of Animation
- 5 Ways to Boost Your Game Juice
- Apply the 12 Principles of Animation to Web Development