From 56e995c3203d3ae621fb09c5a517ca7dfcc55282 Mon Sep 17 00:00:00 2001 From: Preston Farr Date: Sun, 15 Feb 2026 10:45:24 -0700 Subject: [PATCH] feat: add prefers-reduced-motion and prefers-contrast media queries (#5122) * feat: add prefers-reduced-motion and prefers-contrast media queries - Integrate OS prefers-reduced-motion into existing JS toggle system: when OS preference is active, force reduced_motion on and disable the UI checkbox with an explanatory tooltip - Add body.reduced-motion CSS rules for hardcoded animations that bypass the --animation-duration variable (text_segment fade-in, dragover pulse) - Add prefers-contrast: more media query for enhanced focus outlines Co-Authored-By: Claude Opus 4.6 * Support translating title text * Use duration variable * Removed stream fade-in override * Combine hi-contrast selectors --------- Co-authored-by: Claude Opus 4.6 Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com> --- public/scripts/power-user.js | 10 ++++++++++ public/style.css | 25 ++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js index efd289e7d..6e962ee87 100644 --- a/public/scripts/power-user.js +++ b/public/scripts/power-user.js @@ -518,10 +518,20 @@ function switchMessageActions() { } function switchReducedMotion() { + const osReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches; + if (osReduced) { + power_user.reduced_motion = true; + } jQuery.fx.off = power_user.reduced_motion; const overrideDuration = power_user.reduced_motion ? 0 : ANIMATION_DURATION_DEFAULT; setAnimationDuration(overrideDuration); $('#reduced_motion').prop('checked', power_user.reduced_motion); + $('#reduced_motion').prop('disabled', osReduced); + $('#reduced_motion').closest('label').attr('title', + osReduced + ? t`Controlled by your operating system's reduced motion setting` + : t`Disable animations and transitions`, + ); $('body').toggleClass('reduced-motion', power_user.reduced_motion); } diff --git a/public/style.css b/public/style.css index 920f4cec9..450d9ebca 100644 --- a/public/style.css +++ b/public/style.css @@ -318,7 +318,7 @@ input[type='checkbox']:focus-visible { .dragover { filter: brightness(1.1) saturate(1.0); outline: 3px dashed var(--SmartThemeBorderColor); - animation: pulse 0.5s infinite alternate; + animation: pulse var(--animation-duration-3x) infinite alternate; } .dragover.no_animation { @@ -6299,3 +6299,26 @@ body:not(.movingUI) .drawer-content.maximized { border-color: var(--error-color, #e87f7f); background-color: rgba(241, 163, 163, 0.2); } + +@media (prefers-contrast: more) { + :root { + --interactable-outline-color: CanvasText; + --interactable-outline-color-faint: CanvasText; + } + + .interactable:focus-visible, + select:focus-visible, + input:focus-visible, + textarea:focus-visible { + outline-width: 2px; + } + + .mes { + border: 2px solid var(--SmartThemeBorderColor); + } + + .menu_button, + .popup { + border-width: 2px; + } +}