Animations
Durations, easing, what moves and how reduced motion is respected.
Principles
- Motion explains change. Things move to show where they come from and where they go: the tab indicator slides to the new tab, a panel grows out of its button, a sheet slides in from the edge.
- Motion is fast. Durations stay at or below 250ms, so the interface never waits for an animation.
- Motion is optional. Everything works and makes sense without it, for people who turned it off.
Durations
Press play to compare the three durations.
--duration--xx-fast · 50ms · Tiny changes of small controls, e.g. checkbox marks--duration--x-fast · 150ms · Hover, color changes, overlays coming and going--duration--fast · 250ms · Expanding panels, moving indicatorsEasing & transitions
All animations use one easing, ease-in-out. The transition tokens combine duration and easing, ready for the transition property.
| Token | Value |
|---|---|
--easing | ease-in-out |
--transition--xx-fast | var(--duration--xx-fast) var(--easing) |
--transition--x-fast | var(--duration--x-fast) var(--easing) |
--transition--fast | var(--duration--fast) var(--easing) |
.panel {transition:grid-template-rows var(--transition--fast),opacity var(--transition--x-fast);}
What moves
| Element | Animation | Duration |
|---|---|---|
| Hover and focus | Color, background and border | x-fast |
| Tabs, segmented button, on-page menu | Indicator slides to the active item | fast |
| Expansion panel | Height grows from 0 to the content | fast |
| Sheet, modal, popover, blanket | Slide or fade in and out | x-fast |
| Toolbar | Slides in from the bottom | x-fast |
| Views | Offsets of fixed views follow each other | x-fast |
ListGridBoard
The panel grows to its content height with --transition--fast.
Hover me: color changes use --transition--x-fast
Reduced motion
When the operating system asks for reduced motion, fusion-css sets all duration tokens to 0s. Every transition and animation built on the tokens is skipped automatically — one more reason to never hard code durations.
Motion started from JavaScript has to check the media query itself.
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;element.scrollIntoView({behavior: reduceMotion ? "instant" : "smooth"});

