sonar-motion-spatial-fast
200 ms, bounce 0
Small elements: switches, chips, menus.
Short, decelerating, and without bounce by default. The interface is a working tool: motion explains what changed and gets out of the way. A small bounce is kept for two moments that deserve it.
Springs are described as designers talk about them: a duration, the time the spring takes to
settle within 0.2% of its target, and a bounce. The build turns each pair into
a CSS linear() curve, so the motion runs like any transition, with no JavaScript.
Spatial springs move things: position, size, shape. Effects springs change how things look: opacity and color. Effects are quicker, because a fade that lags reads as slowness.
sonar-motion-spatial-fast200 ms, bounce 0
Small elements: switches, chips, menus.
sonar-motion-spatial-default320 ms, bounce 0
Most layout changes: accordions, cards settling, panels resizing.
sonar-motion-spatial-expressive500 ms, bounce 0.3
Only when a dragged card is dropped and for success confirmations.
sonar-motion-effects-fast138 ms, bounce 0
sonar-motion-effects-default212 ms, bounce 0
sonar-motion-effects-slow300 ms, bounce 0
Cubic curves for what is not a spring: leaving the screen, entering panels, the sidebar folding, the theme switch and cards changing columns.
sonar-motion-easing-exit400 ms
Leaving the screen: starts at once and accelerates.
sonar-motion-easing-decelerate400 ms
Entering elements that are not springs, such as panels.
sonar-motion-easing-standard400 ms
Continuous transforms such as the sidebar folding.
sonar-motion-easing-accelerate400 ms
Panels and sheets leaving: starts slow and leaves at speed.
sonar-motion-easing-emphasized400 ms
The theme switch’s knob and cards moving between columns.
sonar-motion-easing-crossfade400 ms
The page cross-fading from one theme to the other.
Fixed durations for the moments that are not a spring. Each is used with the easing named beside it in the guidelines below.
| Token | Value | Use |
|---|---|---|
--sonar-motion-duration-state |
160ms |
Hover and pressed colors of rows, pills and buttons, with easing.decelerate. |
--sonar-motion-duration-panel-enter |
420ms |
A side panel or a phone sheet arriving: its slide uses the spatial default spring stretched to this time. |
--sonar-motion-duration-panel-exit |
150ms |
A side panel leaving: 28 px and out of sight, with easing.accelerate. |
--sonar-motion-duration-sheet-fade |
200ms |
A phone sheet’s opacity while it rises. |
--sonar-motion-duration-sheet-exit |
220ms |
A phone sheet going down, with easing.accelerate. |
--sonar-motion-duration-menu-exit |
110ms |
A menu closing to 96 %, with easing.exit. |
--sonar-motion-duration-dropdown |
180ms |
The search results opening, with easing.decelerate. |
--sonar-motion-duration-tooltip-delay |
300ms |
The pointer rests this long before a tooltip opens. |
--sonar-motion-duration-tooltip-enter |
140ms |
A tooltip opening from 96 %, with easing.decelerate. |
--sonar-motion-duration-tooltip-exit |
90ms |
A tooltip fading out, with easing.exit. |
--sonar-motion-duration-theme |
700ms |
The cross-fade of the whole page when the theme changes, with easing.crossfade. |
--sonar-motion-duration-theme-fallback |
250ms |
Color transitions when a browser cannot cross-fade the page. |
--sonar-motion-duration-reflow |
620ms |
Cards moving to new places when the number of columns changes, with easing.emphasized. |
Changing the theme is two steps. The switch’s knob slides first, in 200 ms on
--sonar-motion-easing-emphasized. At 200 ms the whole page cross-fades into the new theme with a
View Transition: 700 ms on --sonar-motion-easing-crossfade. Nothing changes color out of step,
because the page fades as one picture.
Browsers without View Transitions ease every color over 250 ms instead. With reduced motion requested, the theme changes at once.
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: var(--sonar-motion-duration-theme); /* 700ms */
animation-timing-function: var(--sonar-motion-easing-crossfade); /* cubic-bezier(.4,0,.2,1) */
}
/* Without View Transitions: colors ease */
.sonar-theming, .sonar-theming * {
transition: color var(--sonar-motion-duration-theme-fallback) ease,
background-color var(--sonar-motion-duration-theme-fallback) ease !important;
}
function switchTheme(next) {
const apply = () => (document.documentElement.dataset.theme = next)
if (matchMedia('(prefers-reduced-motion: reduce)').matches) return apply()
if (document.startViewTransition) {
// the knob slides first (200 ms), then the page cross-fades
return setTimeout(() => document.startViewTransition(apply), 200)
}
document.documentElement.classList.add('sonar-theming')
apply()
setTimeout(() => document.documentElement.classList.remove('sonar-theming'), 300)
}
Every spring is two custom properties, a duration and an easing, always used together.
.accordion-panel {
transition: height var(--sonar-motion-spatial-default-duration)
var(--sonar-motion-spatial-default-easing);
}
.menu {
transition: opacity var(--sonar-motion-effects-fast-duration)
var(--sonar-motion-effects-fast-easing);
}
cubic-bezier(.3,0,.8,.15). The search list drops 4 px from 0.98 in 180 ms.
cubic-bezier(.23,1,.32,1).cubic-bezier(.2,0,0,1).