From c5d930f63f888a4f4c183c3b6e353903633ca31c Mon Sep 17 00:00:00 2001 From: Brad Groux <3053586+BradGroux@users.noreply.github.com> Date: Fri, 4 Sep 2026 10:03:17 -0500 Subject: [PATCH] fix: disable unintended reduced-motion layout transitions --- docs/design/TASK-OVERLAY-ACCEPTANCE.md | 2 ++ e2e/task-support-popouts.spec.ts | 6 ++++++ web/src/globals.css | 4 +++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/design/TASK-OVERLAY-ACCEPTANCE.md b/docs/design/TASK-OVERLAY-ACCEPTANCE.md index 6f788c22..376d56d1 100644 --- a/docs/design/TASK-OVERLAY-ACCEPTANCE.md +++ b/docs/design/TASK-OVERLAY-ACCEPTANCE.md @@ -8,6 +8,8 @@ The task workspace retains one mounted content tree through drawer, expanded, an Task confirmations and forms use shared widths and insets, a primary scrolling body, fixed action footers, and quiet Cancel actions. Nested Preview and Conflict Resolver panels become authoring dialogs. Their control bars remain outside the primary scroller. Conflict Resolver's Abort confirmation is inside the shared depth provider, so closing it reactivates the resolver rather than the task behind it. +Reduced-motion preferences make CSS transitions immediate, with no transition delay. A tiny nonzero duration on every element would introduce default `all` transitions and temporarily retain old modal widths, padding, and gaps when text size changes. Footer checks retain exact before/after-scroll geometry rather than waiting away that layout regression. Explicit keyframe animations retain their finite reduced duration for animation-event compatibility. + | Family | Source | Browser geometry evidence | Packaged macOS evidence | | ------------------------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | ----------------------- | | Task root | `TaskDetailPanel`, `UiTaskSurface` | Expanded mode retains section, scroll, board opener | Pending | diff --git a/e2e/task-support-popouts.spec.ts b/e2e/task-support-popouts.spec.ts index 6a8571db..8a8c8874 100644 --- a/e2e/task-support-popouts.spec.ts +++ b/e2e/task-support-popouts.spec.ts @@ -97,6 +97,12 @@ for (const theme of ['light', 'dark']) { }, geometry.fontSize); const footer = dialog.locator('.vk-overlay-footer'); const scroll = dialog.locator('.vk-overlay-scroll'); + if (reducedMotion === 'reduce') { + // A tiny nonzero duration introduces default `all` transitions, + // deferring rem-based padding and width changes by a frame. + await expect(footer).toHaveCSS('transition-duration', '0s'); + await expect(footer).toHaveCSS('transition-delay', '0s'); + } for (const action of actions) { await expect( footer.getByRole('button', { name: action, exact: true }) diff --git a/web/src/globals.css b/web/src/globals.css index d81966dd..e5564d33 100644 --- a/web/src/globals.css +++ b/web/src/globals.css @@ -287,7 +287,9 @@ *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; - transition-duration: 0.01ms !important; + /* Nonzero duration would introduce default `all` layout transitions. */ + transition-duration: 0s !important; + transition-delay: 0s !important; scroll-behavior: auto !important; } }