studio: respect prefers-reduced-motion across animations (#5611)
* studio: respect prefers-reduced-motion across animations Tailwind animate-in/out, Radix dialog/popover zoom-in/slide-in transforms, and the infinite shine / shiny-text / icon-pop keyframes all run at their full duration regardless of the user's OS-level reduced-motion preference. A Playwright probe that emulated the media query confirmed every measured transition was identical between no-preference and reduce, so users with vestibular triggers see the same scaling overlays and continuous shimmers. Add the canonical universal-selector override so animation-duration, animation-iteration-count, and transition-duration collapse to ~0ms when the preference is set, leaving end states intact. Probe re-run shows settings-dialog animationDuration drop from 0.1s to 1e-05s and the 50ms mid-open screenshot is byte-identical to the settled one. * studio: exempt .animate-spin from reduced-motion collapse The universal-selector rule from the previous commit froze every animation including .animate-spin, which is used as the canonical in-progress indicator across Studio: tool execution loaders (tool-ui-python/terminal/web-search/code-execution/fallback/group), sonner toast spinners, Tauri startup + update screens, and the generic <Spinner /> primitive in components/ui/spinner.tsx. Freezing those leaves reduced-motion users with no visual signal that work is in flight, which trades one accessibility win for another. WCAG treats progress indicators as "essential motion" that should keep moving. Restore .animate-spin with a 1.5s cadence (instead of the default 1s) so the rotation is still perceptible but less aggressive than the no-preference path. animation-iteration-count goes back to `infinite` so the spinner doesn't halt after one rotation. Verified via a focused probe that injects a .animate-spin element and a .animate-in fade element side by side: no-preference spin=1s infinite fade=0.15s reduce spin=1.5s infinite fade=1e-05s --------- Co-authored-by: danielhanchen <michaelhan2050@gmail.com>
This commit is contained in:
parent
8d24405440
commit
8059f8d97d
1 changed files with 31 additions and 0 deletions
|
|
@ -1187,3 +1187,34 @@
|
|||
color: var(--popover-foreground) !important;
|
||||
border-color: var(--border) !important;
|
||||
}
|
||||
|
||||
/*
|
||||
* prefers-reduced-motion: honour the OS-level "reduce motion" preference.
|
||||
* Tailwind animate-in/out, Radix open/close transforms, infinite shine/pulse
|
||||
* keyframes, and Framer Motion layout transitions all ignore the media query
|
||||
* by default. Forcing every animation/transition to ~0ms collapses zoom-ins,
|
||||
* slide-ins, and continuous shimmers to a single frame without removing the
|
||||
* end state. Hover colour changes become instant rather than fading, which is
|
||||
* the documented WCAG outcome (motion is "minimised, not removed").
|
||||
*
|
||||
* .animate-spin is the exception: loading spinners are essential progress
|
||||
* indicators across Studio (tool execution loaders, sonner toasts, Tauri
|
||||
* startup / update screens, the <Spinner /> primitive). Freezing them
|
||||
* removes the only visual signal that work is in flight, so they keep
|
||||
* animating but at a slower, less aggressive 1.5s cadence.
|
||||
*/
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
scroll-behavior: auto !important;
|
||||
}
|
||||
|
||||
.animate-spin {
|
||||
animation-duration: 1.5s !important;
|
||||
animation-iteration-count: infinite !important;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue