From 9e7f6d15adf00c3c3ea0c2c09bb9079d83ee6c8a Mon Sep 17 00:00:00 2001 From: RachelElysia <71795832+RachelElysia@users.noreply.github.com> Date: Mon, 15 Jun 2026 13:38:28 -0400 Subject: [PATCH] Fleet UI: Fix dark mode switch flicker on data tables (#47541) --- .../TableContainer/DataTable/_styles.scss | 4 +-- frontend/styles/global/_global.scss | 29 +++++++++++++++++-- frontend/styles/var/colors.scss | 9 +++++- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/frontend/components/TableContainer/DataTable/_styles.scss b/frontend/components/TableContainer/DataTable/_styles.scss index 79cfe81562..e8aa73a47a 100644 --- a/frontend/components/TableContainer/DataTable/_styles.scss +++ b/frontend/components/TableContainer/DataTable/_styles.scss @@ -19,9 +19,9 @@ $shadow-transition-width: 16px; /* Shadows */ linear-gradient( to right, $core-fleet-white, - $transparent + $core-fleet-white-transparent ), - linear-gradient(to left, $core-fleet-white, $transparent), + linear-gradient(to left, $core-fleet-white, $core-fleet-white-transparent), /* Shadow covers */ linear-gradient( to right, diff --git a/frontend/styles/global/_global.scss b/frontend/styles/global/_global.scss index 1e5c739675..7f2db8b108 100644 --- a/frontend/styles/global/_global.scss +++ b/frontend/styles/global/_global.scss @@ -34,11 +34,14 @@ body { body.theme-transition *::after { transition: background-color 300ms ease, color 300ms ease, border-color 300ms ease, box-shadow 300ms ease, fill 300ms ease, - stroke 300ms ease !important; + stroke 300ms ease, background-image 300ms ease !important; } - // Hide the gradient image during theme switch so background-color - // can transition smoothly without the gradient snapping. + // The core-wrapper's hero gradient doesn't interpolate cleanly between + // themes (different shape/stops), so hide it during the transition and + // let background-color carry the fade. The data-table wrapper keeps its + // gradient — it has the same shape in both themes, so background-image + // interpolates smoothly along with background-color. body.theme-transition .core-wrapper { background-image: none !important; } @@ -285,6 +288,26 @@ body.dark-mode tbody tr { background-color: $dark-mode-table-row; } +// Data table rows stay transparent in dark mode so the wrapper's scroll +// shadow can show through when the table is horizontally scrollable — +// matches the light-mode pattern where `tr` has no background and the +// wrapper shows through. +body.dark-mode .data-table-block tbody tr { + background-color: transparent; +} + +// $ui-off-white-opaque is a near-transparent rgba tuned for light mode; +// against the dark wrapper it's perceptually invisible. A translucent +// black overlay darkens the row beneath the wrapper color cleanly — the +// interpolation from `transparent` (rgba(0,0,0,0)) to rgba(0,0,0,0.2) +// stays in monotonically darkening tints, so no flicker. Selector +// includes `.data-table` to beat the component rule's `.single-row:hover` +// specificity (0,4,2). +body.dark-mode .data-table-block .data-table tbody tr:hover, +body.dark-mode .data-table-block .data-table tbody .single-row:hover { + background-color: rgba(0, 0, 0, 0.2); +} + body.dark-mode .site-nav-item:not(.dup-org-logo):hover { background-color: $dark-mode-nav-hover; } diff --git a/frontend/styles/var/colors.scss b/frontend/styles/var/colors.scss index 76fa9b45c5..f5be7f7326 100644 --- a/frontend/styles/var/colors.scss +++ b/frontend/styles/var/colors.scss @@ -12,6 +12,11 @@ --core-fleet-black: #192147; --core-fleet-green: #009a7d; --core-fleet-white: #ffffff; + // Same RGB as --core-fleet-white with zero alpha. Use as the fade-out + // endpoint in gradients that need to disappear into the wrapper background + // cleanly. The generic `$transparent` is rgba(255, 255, 255, 0) regardless + // of theme, which leaks white into dark-mode gradients. + --core-fleet-white-transparent: rgba(255, 255, 255, 0); --ui-fleet-black-75: #515774; --ui-fleet-black-50: #8b8fa2; --ui-fleet-black-33: #b3b6c1; @@ -118,6 +123,7 @@ body.dark-mode { --core-fleet-black: #e2e4ea; --core-fleet-green: #00c28b; --core-fleet-white: #1a1c21; + --core-fleet-white-transparent: rgba(26, 28, 33, 0); --ui-fleet-black-75: #bebebf; --ui-fleet-black-50: #87888b; --ui-fleet-black-33: #636777; @@ -147,7 +153,7 @@ body.dark-mode { --ui-gray: #32363e; --ui-light-grey: #1e2128; --ui-off-white: #1e2128; - --ui-shadow: #000000; + --ui-shadow: #2a2e36; --ui-vibrant-blue-50: rgba(123, 121, 255, 0.3); --ui-vibrant-blue-25: #282736; --ui-vibrant-blue-10: #2d2e4d; @@ -219,6 +225,7 @@ body.dark-mode { $core-fleet-black: var(--core-fleet-black); $core-fleet-green: var(--core-fleet-green); $core-fleet-white: var(--core-fleet-white); +$core-fleet-white-transparent: var(--core-fleet-white-transparent); $ui-fleet-black-75: var(--ui-fleet-black-75); $ui-fleet-black-50: var(--ui-fleet-black-50); $ui-fleet-black-33: var(--ui-fleet-black-33);