Duration and motion tokens
A duration scale plus easing curves as tokens, with a prefers-reduced-motion override that zeros all durations — accessible animation in one rule.
Hover a row to see the transition at that duration
Quick implementation
:root {
/* Duration scale */
--dur-instant: 50ms; /* state indicators, selection */
--dur-fast: 120ms; /* hover states, tooltips */
--dur-base: 200ms; /* most transitions */
--dur-slow: 350ms; /* panels, modals entering */
--dur-slower: 500ms; /* page transitions, hero elements */
/* Easing curves */
--ease-linear: linear;
--ease-out: cubic-bezier(0.0, 0.0, 0.2, 1); /* decelerate */
--ease-in: cubic-bezier(0.4, 0.0, 1.0, 1); /* accelerate */
--ease-in-out: cubic-bezier(0.4, 0.0, 0.2, 1); /* standard */
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);/* slight overshoot */
}
/* Accessibility: zero all durations for reduced-motion users.
Using the tokens means this one block covers every animation. */
@media (prefers-reduced-motion: reduce) {
:root {
--dur-instant: 0ms;
--dur-fast: 0ms;
--dur-base: 0ms;
--dur-slow: 0ms;
--dur-slower: 0ms;
}
}
/* Usage */
.btn {
transition: background var(--dur-fast) var(--ease-out),
box-shadow var(--dur-base) var(--ease-out);
}
.modal {
transition: opacity var(--dur-base) var(--ease-in-out),
transform var(--dur-slow) var(--ease-out);
}
Prompt this to your LLM
Includes role, constraints, framework variants, and edge cases.
You are a senior frontend engineer building a motion token system
for a design system.
Goal: Create CSS custom property tokens for animation durations
and easing curves, with built-in reduced-motion support.
Duration scale:
- --dur-instant (50ms): state feedback (checkbox check, badge update)
- --dur-fast (120ms): hover states, tooltips
- --dur-base (200ms): most UI transitions
- --dur-slow (350ms): panels, drawers, modals entering
- --dur-slower (500ms): page transitions, large element animations
Easing tokens:
- --ease-out (decelerate): elements entering from off-screen
- --ease-in (accelerate): elements leaving to off-screen
- --ease-in-out (standard): toggling visible/hidden
- --ease-spring (slight overshoot): interactive/playful elements
Accessibility:
- Show the prefers-reduced-motion override that zeros all duration
tokens — explain why this is better than writing individual
@media (prefers-reduced-motion: reduce) blocks per component
Framework variant: Show how to expose these tokens as a JavaScript
object for use with Framer Motion or React Spring animations.
Return only CSS with inline comments.
Why token-based reduced-motion is better
The naive reduced-motion approach wraps each animation in its own media query: @media (prefers-reduced-motion: reduce) { .btn { transition: none } }. This doesn't scale — every animated component needs its own override. With duration tokens, @media (prefers-reduced-motion: reduce) { :root { --dur-base: 0ms } } zeros every animation in the system at once. Components don't need to know about reduced-motion; they just use var(--dur-base) and it becomes zero automatically for users who prefer it.
Choosing the right duration
UI response should feel instant below 100ms — users perceive it as direct manipulation. Between 100–300ms feels like smooth UI response. Above 300ms starts to feel slow unless the element is large (a full-screen modal entering) or the animation is the primary feedback (a loading state). The rule: transitions should be shorter than the user's attention span for that action. Hover states at 350ms feel sluggish — 120ms is correct. Full-panel slides at 120ms feel jarring — 350ms gives the eye time to track the motion.