Skip to content

Fix #1309: declare color-scheme so native UA surfaces follow dark mode - #1324

Merged
rumblefrog merged 1 commit into
mainfrom
fix/issue-1309-color-scheme
May 10, 2026
Merged

rumblefrog merged 1 commit into
mainfrom
fix/issue-1309-color-scheme

Conversation

@rumblefrog

Copy link
Copy Markdown
Member

Fixes #1309.

Summary

  • Add color-scheme: light to :root and color-scheme: dark to html.dark in web/themes/default/css/theme.css so the browser paints native UA surfaces (the open <select> dropdown panel, native scrollbars, <input type="date|time|color"> pickers, and form autofill highlighting) in the matching scheme. Pre-fix the chrome's dark tokens swapped correctly for DOM-rendered surfaces, but anything painted in the browser's top-layer system UI ignored html.dark and rendered light — most jarring on mobile (iOS Safari especially) where the native <select> picker full-screens, sliding a stark-white sheet over an otherwise-dark ?p=banlist page when the user tapped the Server / Time / Type filter.
  • Add web/tests/e2e/specs/a11y/color-scheme.spec.ts as the regression guard. Asserts getComputedStyle(document.documentElement).colorScheme resolves to dark under pinned dark mode and light under pinned light mode, using the same pinTheme(localStorage['sbpp-theme'] + waitForFunction) helper shape as a11y/dark-theme-contrast.spec.ts. Chromium-only (the rule is token-driven; viewport doesn't change the computed value, and the mobile symptom — full-screen picker — is painted outside the DOM so JS can't read it at any viewport).
  • Add a "Where to find what" row in AGENTS.md next to the existing prefers-reduced-motion row so future contributors find the color-scheme declarations + the regression spec without grepping.

The fix is the literal suggested fix in the issue body. The prefers-color-scheme media query the JS theme resolver consumes (web/themes/default/js/theme.js) reads the OS preference, not the page's declared scheme, so the existing system-pref / toggle path is unaffected.

Test plan

Ran locally against this worktree's stack (sbpp-task-1309):

  • ./sbpp.sh phpstan — pass (No errors, 228 files analysed at level 5).
  • ./sbpp.sh test — pass (403 tests, 1765 assertions; the one PHPUnit deprecation pre-exists on main).
  • ./sbpp.sh e2e --grep "color-scheme" — both new tests pass on chromium; mobile-chromium project skips by design.
  • ./sbpp.sh e2e --grep "dark-theme contrast|theme toggle" — 13 passed / 7 skipped (no regressions in the related dark-theme + theme-toggle gates).

Skipped (no surface touched):

  • ./sbpp.sh ts-check — no .js / .ts changes.
  • ./sbpp.sh composer api-contract — no API handler changes.

…de (#1309)

The chrome's `:root` / `html.dark` token blocks swap CSS custom
properties for DOM-rendered surfaces, but that has no effect on
surfaces the browser paints in its top-layer system UI: the open
`<select>` dropdown panel, native scrollbars, `<input type="date|
time|color">` pickers, and form autofill highlighting. Without a
declared `color-scheme`, the browser uses its UA default (light)
for those surfaces regardless of `html.dark`.

The result is most jarring on mobile (iOS Safari, several Android
Chromes) where the native `<select>` picker full-screens — opening
a Server / Time / Type filter on `?p=banlist` slides a stark-white
sheet over an otherwise dark page. Desktop scrollbars and autofill
highlighting flash light too.

Fix: add `color-scheme: light` to `:root` and `color-scheme: dark`
to `html.dark`. The browser then renders the matching scheme for
the system surfaces above. The `prefers-color-scheme` media query
the JS theme resolver consumes (`web/themes/default/js/theme.js`)
reads the OS preference, not the page's declared scheme, so the
existing system-pref / toggle path is unaffected.

Regression test: `web/tests/e2e/specs/a11y/color-scheme.spec.ts`
locks `getComputedStyle(document.documentElement).colorScheme`
under both pinned themes via the same `pinTheme` helper shape as
`a11y/dark-theme-contrast.spec.ts`. The mobile symptom (full-screen
picker) is painted outside the DOM so it can't be read by JS at any
viewport, but the contract under test (the declared property) is
the upstream cause.

Fixes #1309
@rumblefrog
rumblefrog added this pull request to the merge queue May 10, 2026
Merged via the queue into main with commit cd72312 May 10, 2026
4 checks passed
@rumblefrog
rumblefrog deleted the fix/issue-1309-color-scheme branch May 10, 2026 21:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Native <select> dropdown panel + scrollbars render light in dark mode (missing color-scheme)

1 participant