Animation basics
The principles of a good animation, progress → easing → interpolation, which tool to pick, the minimal basics.
Updated
What makes a good animation
A good animation explains: where an element came from, where it went, what changed, that your action had an effect. A bad one just slows the user down. Before the tools, 5 ideas that make the difference between "it works" and "it looks professional":
| Principle | What it means | Example |
|---|---|---|
| a short duration | 150–300 ms for UI, rarely over 500 ms | a dropdown that appears in 200 ms |
| easing | nothing real moves linearly | ease-out on entrance |
| stagger | a list's items start one after another, not all at once | cards appearing one after another, 60 ms apart |
| a small distance | 8–24 px movements, not across the screen | y: 16 → 0 + opacity: 0 → 1 |
| continuity | the element transforms, it doesn't disappear and reappear | a card that expands into the detail page |
And the technical rule: animate transform and opacity — see Transitions and animations in CSS.
The 3 numbers behind every animation
Every library, under the hood, does the same calculation on every frame (~60 per second):
- progress
tfrom 0 to 1 = elapsed time / duration; - easing: turns
tinto a "felt" progress —easeOutCubic(t) = 1 - (1 - t)³; - interpolation (lerp): the current value =
start + (end - start) × progress.
const lerp = (a, b, t) => a + (b - a) * t
const easeOutCubic = t => 1 - (1 - t) ** 3
lerp(0, 100, easeOutCubic(0.5)) // 87.5 — halfway through the time, already close to the endSprings (Motion) have no fixed duration: they simulate a spring with stiffness and damping — that's why they feel natural and can be interrupted without a jump.
The tools — which and when
| Tool | For | Size | When |
|---|---|---|---|
| CSS (transition, @keyframes) | hover, focus, simple entrances | 0 KB | always first |
| The View Transitions API | transitions between states / pages | 0 KB | morphing between lists and details |
Motion (motion/react) |
declarative animations in React: enter, exit, layout, gestures, scroll | medium | the default in React |
| GSAP | complex timelines, scroll storytelling, animated text, SVG | medium | landing pages, showcase sites |
| Lottie | animations drawn in After Effects | varies | animated illustrations |
| Three.js / R3F | 3D, WebGL | big | 3D experiences |
The shortest basics to get started
Three recipes cover 80% of what you see on sites that "look good":
1. Reveal on scroll (CSS only, no JS):
.reveal {
animation: reveal linear both;
animation-timeline: view();
animation-range: entry 0% entry 60%;
}
@keyframes reveal {
from { opacity: 0; transform: translateY(24px); }
}2. A list that enters with a stagger (Motion):
<motion.ul initial="hidden" animate="show" variants={{ show: { transition: { delayChildren: stagger(0.06) } } }}>
{items.map(item => (
<motion.li key={item.id} variants={{ hidden: { opacity: 0, y: 16 }, show: { opacity: 1, y: 0 } }} />
))}
</motion.ul>3. Feedback on interaction (Motion):
<motion.button whileHover={{ scale: 1.03 }} whileTap={{ scale: 0.97 }}>Save</motion.button>Details in the Motion and GSAP lessons; complete examples in Interesting examples.
Accessibility
Respect prefers-reduced-motion — in CSS with a media query, in Motion with useReducedMotion() or <MotionConfig reducedMotion="user">, in GSAP with gsap.matchMedia(). Don't animate things that flash more than 3 times per second.
Summary
- Short (150–300 ms),
ease-out, stagger, small distances, onlytransformandopacity. - Every animation = progress → easing → interpolation.
- CSS first; Motion for React; GSAP for timelines and complex scroll; respect reduced motion.