Skip to content

The site's theme is scoped to a wrapper div, so the page canvas ignores it #89

Description

@Muawiya-contact

ThemeProvider renders the themed element as a plain div inside
#root:

return (
  <ThemeContext.Provider value={value}>
    <div data-theme={theme}>{children}</div>
  </ThemeContext.Provider>
)

and every theme variable — including color-scheme — is declared on that
selector:

[data-theme='dark'] { --bg: #0b0d10; ... color-scheme: dark; }

color-scheme and the page background are the two things a browser reads
off the root element, not off a div, so neither reaches the document.
Measured against npm --prefix site run dev:

getComputedStyle(document.documentElement).colorScheme  // "normal"
getComputedStyle(document.body).colorScheme             // "normal"
getComputedStyle(themedDiv).colorScheme                 // "dark"
getComputedStyle(document.documentElement).backgroundColor // rgba(0, 0, 0, 0)
getComputedStyle(document.body).backgroundColor            // rgba(0, 0, 0, 0)
getComputedStyle(document.querySelector('.app-shell')).backgroundColor // rgb(11, 13, 16)

So the only thing painting the site's background is .app-shell, and the
canvas behind it belongs to the visitor rather than to the site. Emptying
#root — which is exactly the markup index.html ships, and exactly what
the browser paints between parsing the HTML and the deferred
src/main.jsx module mounting React — shows what that canvas is:

  • with the browser in light mode: a white page
  • with the browser in dark mode: a dark page

Reproduce both by toggling the emulated prefers-color-scheme in DevTools
(Rendering panel) and running document.getElementById('root').innerHTML = ''.

Three consequences, all for a visitor whose browser is in light mode,
which is most of them:

  • a white flash on every cold load, before the bundle mounts the dark UI;
  • the overscroll/rubber-band area above and below the page is white while
    the page is near-black;
  • UA-drawn scrollbars and controls render light against the dark page,
    because color-scheme: dark never reached the root.

The theme toggle changes none of it — it flips an attribute the canvas
cannot see.

The desktop app already does this right: app/src/styles.css:3 puts
color-scheme on :root. The fix here is the same shape — set the
attribute on document.documentElement from a useEffect in
ThemeProvider instead of wrapping the children in a div, and give
html, body background: var(--bg) so the canvas is painted too.

Verified in the running dev server: setting data-theme="dark" on <html>
and adding body { background: var(--bg) } gives
getComputedStyle(document.documentElement).colorScheme === "dark" and
paints the canvas rgb(11, 13, 16) with #root still empty and the
browser still in light mode.

site/src/context/ThemeContext.jsx:26 · site/src/styles/index.css:6 · site/src/styles/index.css:43

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workinggood first issueGood for newcomersjavascriptPull requests that update javascript codepriority: lowNice to have

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions