Repository navigation
theme="light" attribute does not override prefers-color-scheme: dark #2999
Description
Summary
Setting theme="light" on a <math-field> has no effect when the user's OS / browser reports prefers-color-scheme: dark. The mathfield continues to render with dark‑mode colors. theme="dark" on a light system works correctly, so the bug is specifically a missing [theme='light'] rule to counter the dark media query.
Environment
- MathLive 0.109.1 (tested on https://mathlive.io/mathfield/demo/)
- Chromium (Playwright),
prefers-color-scheme: darkemulated via DevTools - Google Chrome Version 147.0.7727.56 (Official Build) (arm64)
Related
- Dark Mode Override #2769 "Dark Mode Override" was closed with the guidance "Adding the
themeattribute is the supported method." This issue shows that the supported method does not work fortheme="light"when the OS reportsprefers-color-scheme: dark— there is no matching CSS rule for it. - [FEATURE] Set mathlive theme(DARK OR LIGHT) programatically #1722 originally introduced the
themeattribute.
Steps to reproduce
- Open the MathLive demo.
- In Chrome DevTools → Rendering → emulate CSS media feature
prefers-color-scheme: dark. - Inspect the
<math-field>element and settheme="light". - Observe: the neutrals, caret, selection and placeholder colors remain the dark‑mode values.
Expected
theme="light" should fully override prefers-color-scheme: dark, mirroring the behavior of theme="dark" on light systems.
Actual (computed values, OS=dark)
| Attribute | --neutral-100 |
--neutral-900 |
--_selection-background-color |
--_placeholder-color |
|---|---|---|---|---|
| (none) | #121212 |
#f5f5f5 |
hsl(212, 65%, 55%) |
hsl(212, 60%, 69%) |
theme="light" |
#121212 |
#f5f5f5 |
hsl(212, 65%, 55%) |
hsl(212, 60%, 69%) |
No variable changes when theme="light" is added. Symmetric test (theme="dark" on light OS) correctly flips --neutral-100 from #f5f5f5 → #121212.
Root cause
The CSS defines prefers-color-scheme: dark media queries and :host([theme='dark']) rules, but no :host([theme='light']) counterpart. Runtime scan of the demo's stylesheets:
:host([theme='dark'])blocks: 2@media (prefers-color-scheme: dark)blocks: 4[theme='light']blocks: 0
Relevant sources:
src/ui/colors/colors.less:169-213—@media (prefers-color-scheme: dark) :host { … }and:host([theme='dark']) { … }, no light counterpart.css/mathfield.less:124—@media (prefers-color-scheme: dark) .ML__container { … }with no[theme='light'] .ML__containerreset.src/ui/style.less:77— same pattern.
Because the dark media query and the (missing) light attribute selector have comparable specificity and no explicit light rule exists, the dark media‑query values persist once they apply.
Reproduction script (Playwright)
await page.goto('https://mathlive.io/mathfield/demo/');
await page.emulateMedia({ colorScheme: 'dark' });
const result = await page.evaluate(() => {
const mf = document.querySelector('math-field');
const read = () => getComputedStyle(mf).getPropertyValue('--neutral-100').trim();
const before = read();
mf.setAttribute('theme', 'light');
return { before, after: read() };
});
// => { before: '#121212', after: '#121212' } // expected after: '#f5f5f5'Suggested fix
Mirror every @media (prefers-color-scheme: dark) block with a :host([theme='light']) / [theme='light'] .ML__container block that re‑asserts the light values, or restructure so the dark values live behind :host(:not([theme='light'])) inside the media query. Files to touch: src/ui/colors/colors.less, css/mathfield.less, src/ui/style.less, and the corresponding dark‑block in css/virtual-keyboard.less and css/keystroke-caption.less for consistency.
Investigation and drafting of this issue was assisted by AI (Claude Code). The live reproduction, CSS sources, and computed‑value measurements were verified before filing.
Activity