From a51c537bb2f75924cf2c5494f32b168b8aaeb50a Mon Sep 17 00:00:00 2001 From: 4gray <4gray@users.noreply.github.com> Date: Sun, 12 Jul 2026 17:24:49 +0200 Subject: [PATCH] fix(theme): make scrollbars follow the app theme instead of the OS color scheme (#1179) On Windows with a light OS theme, scrollbars rendered light even when the app was switched to dark. Two combined causes: - The page never declared `color-scheme`, so Chromium colored native scrollbars from the OS preference. Declare `color-scheme: light` on html and flip it to `dark` via `html:has(> body.dark-theme)` plus the `.dark-theme` block itself. - Scrollbar styling referenced `--mat-sys-*` tokens, which are never emitted by the current Material theme setup (mat.define-theme + all-component-themes does not produce system tokens). Those `scrollbar-color` declarations computed to `auto`, falling back to the native (light) scrollbar. Switch scrollbar styling to the `--app-muted-color` design token (defined for both themes), replace hardcoded white `rgba(255,255,255,.08)` thumbs, and add an explicit `scrollbar-color` where only `scrollbar-width: thin` was set. Verified live in Electron via CDP in both themes: scrollbar-color resolves and scrollbars render dark in dark theme regardless of the OS setting. Co-authored-by: Claude Fable 5 --- apps/web/src/styles.scss | 23 +++++++++++++++++-- .../category-content-view.component.scss | 3 ++- .../live-stream-layout.component.scss | 3 ++- .../epg-progress-panel.component.scss | 2 ++ .../embedded-mpv-player.component.scss | 2 ++ libs/ui/styles/_detail-view.scss | 6 +++++ .../workspace-command-palette.component.scss | 3 ++- .../workspace-context-panel.component.scss | 3 ++- 8 files changed, 39 insertions(+), 6 deletions(-) diff --git a/apps/web/src/styles.scss b/apps/web/src/styles.scss index 60e038639..4e9fc76c3 100644 --- a/apps/web/src/styles.scss +++ b/apps/web/src/styles.scss @@ -108,6 +108,20 @@ body.frameless-platform #epg-navigation { } // ─── Base ───────────────────────────────────────────────────────────────────── +// Native UI (scrollbars, form controls, popups) must follow the app theme, +// not the OS preference. Chromium colors unstyled/native scrollbars from the +// element's color-scheme, so declare it explicitly for both themes. +html { + color-scheme: light; +} + +// The root scroller (html) sits outside body.dark-theme, so flip it via +// :has(); the color-scheme declaration in .dark-theme below keeps the body +// subtree covered in engines without :has() support. +html:has(> body.dark-theme) { + color-scheme: dark; +} + body, html { user-select: none; @@ -155,6 +169,7 @@ textarea, // ─── Dark Theme ─────────────────────────────────────────────────────────────── .dark-theme { background: var(--mat-sys-surface) !important; + color-scheme: dark; // Refined scrollbar for dark mode ::-webkit-scrollbar { @@ -167,11 +182,15 @@ textarea, } ::-webkit-scrollbar-thumb { - background-color: var(--mat-sys-outline-variant); + background-color: color-mix( + in srgb, + var(--app-muted-color) 70%, + transparent + ); border-radius: 999px; &:hover { - background-color: var(--mat-sys-outline); + background-color: var(--app-muted-color); } } } diff --git a/libs/portal/catalog/feature/src/lib/category-content-view/category-content-view.component.scss b/libs/portal/catalog/feature/src/lib/category-content-view/category-content-view.component.scss index 36340c715..a55858215 100644 --- a/libs/portal/catalog/feature/src/lib/category-content-view/category-content-view.component.scss +++ b/libs/portal/catalog/feature/src/lib/category-content-view/category-content-view.component.scss @@ -245,7 +245,8 @@ app-grid-list { padding: 16px 20px 20px; display: block; scrollbar-width: thin; - scrollbar-color: rgba(255, 255, 255, 0.08) transparent; + scrollbar-color: color-mix(in srgb, var(--app-muted-color) 55%, transparent) + transparent; } @media (max-width: 768px) { diff --git a/libs/portal/xtream/feature/src/lib/live-stream-layout/live-stream-layout.component.scss b/libs/portal/xtream/feature/src/lib/live-stream-layout/live-stream-layout.component.scss index ee772f77f..6bbc80b9f 100644 --- a/libs/portal/xtream/feature/src/lib/live-stream-layout/live-stream-layout.component.scss +++ b/libs/portal/xtream/feature/src/lib/live-stream-layout/live-stream-layout.component.scss @@ -77,7 +77,8 @@ app-grid-list.live-all-items-grid { overflow-y: auto; padding: 16px 20px 20px; scrollbar-width: thin; - scrollbar-color: rgba(255, 255, 255, 0.08) transparent; + scrollbar-color: color-mix(in srgb, var(--app-muted-color) 55%, transparent) + transparent; } .loading-indicator { diff --git a/libs/ui/epg/src/lib/epg-progress-panel/epg-progress-panel.component.scss b/libs/ui/epg/src/lib/epg-progress-panel/epg-progress-panel.component.scss index f3d46d3c2..61914a45c 100644 --- a/libs/ui/epg/src/lib/epg-progress-panel/epg-progress-panel.component.scss +++ b/libs/ui/epg/src/lib/epg-progress-panel/epg-progress-panel.component.scss @@ -120,6 +120,8 @@ overflow-y: auto; padding: 4px 0; scrollbar-width: thin; + scrollbar-color: color-mix(in srgb, var(--app-muted-color) 55%, transparent) + transparent; } .import-item { diff --git a/libs/ui/playback/src/lib/embedded-mpv-player/embedded-mpv-player.component.scss b/libs/ui/playback/src/lib/embedded-mpv-player/embedded-mpv-player.component.scss index 94e4fca2d..2206462b6 100644 --- a/libs/ui/playback/src/lib/embedded-mpv-player/embedded-mpv-player.component.scss +++ b/libs/ui/playback/src/lib/embedded-mpv-player/embedded-mpv-player.component.scss @@ -454,6 +454,8 @@ max-height: 240px; overflow-y: auto; scrollbar-width: thin; + scrollbar-color: color-mix(in srgb, var(--app-muted-color) 55%, transparent) + transparent; } .embedded-mpv-player__audio-track { diff --git a/libs/ui/styles/_detail-view.scss b/libs/ui/styles/_detail-view.scss index 49f8c0f50..e07d954cc 100644 --- a/libs/ui/styles/_detail-view.scss +++ b/libs/ui/styles/_detail-view.scss @@ -223,6 +223,12 @@ overflow-x: auto; padding-bottom: 8px; scrollbar-width: thin; + scrollbar-color: color-mix( + in srgb, + var(--app-muted-color) 55%, + transparent + ) + transparent; } &__similar-card { diff --git a/libs/workspace/shell/feature/src/lib/workspace-command-palette/workspace-command-palette.component.scss b/libs/workspace/shell/feature/src/lib/workspace-command-palette/workspace-command-palette.component.scss index d1ac130d1..1fe3199f0 100644 --- a/libs/workspace/shell/feature/src/lib/workspace-command-palette/workspace-command-palette.component.scss +++ b/libs/workspace/shell/feature/src/lib/workspace-command-palette/workspace-command-palette.component.scss @@ -89,7 +89,8 @@ overflow-x: hidden; padding: 6px; scrollbar-width: thin; - scrollbar-color: var(--mat-sys-outline-variant) transparent; + scrollbar-color: color-mix(in srgb, var(--app-muted-color) 55%, transparent) + transparent; } // ─── Group ─────────────────────────────────────────────────────────────────── diff --git a/libs/workspace/shell/feature/src/lib/workspace-context-panel/workspace-context-panel.component.scss b/libs/workspace/shell/feature/src/lib/workspace-context-panel/workspace-context-panel.component.scss index e2e03a3f5..084577aca 100644 --- a/libs/workspace/shell/feature/src/lib/workspace-context-panel/workspace-context-panel.component.scss +++ b/libs/workspace/shell/feature/src/lib/workspace-context-panel/workspace-context-panel.component.scss @@ -177,7 +177,8 @@ app-workspace-context-category-view { overflow-x: hidden; overscroll-behavior: contain; scrollbar-width: thin; - scrollbar-color: var(--mat-sys-outline-variant) transparent; + scrollbar-color: color-mix(in srgb, var(--app-muted-color) 55%, transparent) + transparent; } .context-skeleton {