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
.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
.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;
}
<div class="wrapper">
<div class="greeting">
Hi there
<span class="hand">👋</span>
</div>
</div>
Using Transitions 👷
Questions?
.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);
}
📏 Shorthand Syntax
.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);
}
Multi Property Transitions ♾️
.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);
}
🤏 Multi Property Transition Shorthand
.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);
}
Combining Transitions 🤝
.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);
}
Timing ⏱️ Functions
.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);
}
⏪ 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?
.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);
}
}
State Based Animations 🔛
.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);
}
}
Multi Property Animations 🍿
.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);
}
}
⏪ 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?
<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
<div class="view-transitions-wrapper">
<h1 class="view-transitions-content">CONTENT</h1>
</div>
CONTENT
Understanding the Transition 🤔
Questions?
/* 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
transformfilteropacity
- 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
.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);
}
}
2. Anticipation ⌛
Using small actions to indicate an action is about to happen
.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);
}
3. Follow Through and Overlap 🐾
Adding movement after an action
.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;
}
}
4. Arcs ⭕
Nature moves in arcs
.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;
}
}
5. Slow In & Slow Out 🦥
Easing in and out of an action
.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);
}
6. Timing ⌚
Number of frames for a given action
.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);
}
}
7. Secondary Action 🔂
Additional actions that enhance an action
.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);
}
}
8. Exaggeration 💥
Provide dramatic effect
.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);
}
}
9. Staging 🎭
Direct the audience attention
.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);
}
}
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
.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);
}
}
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