Skip to content

Browsers force-dark the site because we never declare a color scheme #557

Description

@VasiaKoum

Symptom

A user (during the user testing) viewing the site on their phone in dark mode most of the elements rendered dark.

Cause

We have no dark theme at all. tailwind.config.ts sets darkMode: ["class"], but nothing in the app ever applies that class: there is no next-themes, no ThemeProvider, and no classList.add('dark') anywhere in src/. The .dark token block in src/app/globals.css is dead code, and the ~31 dark: variants scattered through the components never activate.

What the user saw was the browser repainting the page. Chrome on Android ("Auto dark theme"), Samsung Internet, and Android WebView in-app browsers all algorithmically invert pages that don't declare a color scheme. That algorithm is selective — it darkens light backgrounds and lightens dark text but skips images and many computed colours — which is exactly why only some elements changed.

The trigger is that we declare nothing. We have no color-scheme and no prefers-color-scheme query anywhere in the codebase, so to those browsers the page looks light-only by accident rather than by intent, and they "help".

Fix

Declare the scheme explicitly, in two places:

  1. colorScheme: 'only light' on the viewport export in src/app/layout.tsx. This renders <meta name="color-scheme" content="only light">, the documented opt-out from Chrome's Auto Dark Theme.
  2. color-scheme: only light on :root in src/app/globals.css. This covers UA-drawn surfaces the meta tag doesn't reach — scrollbars, <select> dropdowns, date pickers — which follow the OS scheme on their own.

Caveats

  • This does not stop Android's system-level Force dark (the accessibility/developer override, as opposed to the Chrome setting). Worth confirming with the reporting user which setting they had enabled.
  • Older Samsung Internet versions honour color-scheme inconsistently.

Open question

only light suppresses the browser's dark mode. The alternative is to actually ship one — the .dark token block is already complete and unused, so the work would be mostly wiring next-themes and letting those tokens activate. Right now we get neither: no dark theme of our own, and browsers inventing a poor one.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions