New Tab does not pick up High Contrast Mode on Linux and macOS
Categories
(Firefox :: New Tab Page, defect, P2)
Tracking
()
| Tracking | Status | |
|---|---|---|
| firefox-esr115 | --- | unaffected |
| firefox-esr140 | --- | unaffected |
| firefox-esr153 | --- | unaffected |
| firefox156 | --- | unaffected |
| firefox157 | --- | wontfix |
| firefox158 | --- | verified |
People
(Reporter: dao, Assigned: dao)
References
Details
(Keywords: access, Whiteboard: [sng][mcab-hnt])
Attachments
(2 files)
Turning on the OS high-contrast setting leaves New Tab looking as it does normally while the surrounding chrome switches to high-contrast colors. Reported against the New Tab search bar, but it applies to New Tab's other surfaces too.
browser/extensions/newtab/content-src/styles/nova/_tokens.scss declares :root.nova-tokens { … } outside any cascade layer, so it outranks every @layer in tokens-shared.css and tokens-brand.css, tokens-prefers-contrast included. It carries a @media (forced-colors) counterpart but no @media (prefers-contrast) one.
The platform split follows from where each signal lands. prefers-contrast tracks the OS setting in both the chrome and the content realm everywhere. forced-colors never applies to a chrome document, and in content it follows browser.display.document_color_use, which defaults to 0 (mirror the OS setting) on Windows and 1 (off) on Linux and macOS. So on Windows the shim's forced-colors block covers most of the gap; on Linux and macOS prefers-contrast is the only signal reaching the page, and the shim eats it.
Measured on about:newtab with ui.useAccessibilityTheme=1, by removing the nova-tokens class from the page root and diffing the 47 tokens the toolkit sheets override under prefers-contrast:
- Linux and macOS default (
browser.display.document_color_use=1, no forced colors): 31 of the 47 resolve to the wrong value. A further 9 differ only in hex case and are the same color. - Windows default with OS HCM (
document_color_use=0, forced colors active as well): 14 resolve to the wrong value, the rest being covered by the shim'sforced-colorsblock or by Gecko's own forced-color adjustment.
A representative sample, New Tab against the address bar, under prefers-contrast:
token New Tab address bar
--border-color light-dark(#B7B6BA, #949297) CanvasText
--text-color light-dark(#180E30, #F2F0F8) CanvasText
--icon-color light-dark(#180E30, #F2F0F8) CanvasText
--background-color-canvas light-dark(#F7F6FB, #131215) Canvas
--toolbar-field-background-color light-dark(#ffffff, #252428) Field
--toolbar-field-border-color light-dark(#D6D5DA, #3F3E42) CanvasText
--toolbar-field-text-color light-dark(#3E315F, #E7E1F8) FieldText
Under forced colors the wrong ones include --panel-background-color (Canvas where the shared sheet says Menu), --panel-text-color (a literal where it should be MenuText), --toolbarbutton-outline-color-selected (ButtonText for SelectedItem), the five --icon-color* tokens and --text-color.
The file is generated by mach buildtokens from the *.nova.tokens.json inputs, so the fix belongs in the generator: emit each block inside the cascade layer that matches it. Either way it changes how every New Tab surface renders under high contrast, not just the search bar.
Confirmed the structure described in comment 0, and it localizes one level below the SCSS: the defect is in the mach buildtokens generator, not the generated file.
Root cause. browser/extensions/newtab/content-src/styles/nova/_tokens.scss is emitted by the newtab formatter, which has two gaps the desktop formatter does not:
-
No
prefersContrastbucket at all. get-newtab-tokens-by-layer.mjs builds only{ foundation, forcedColors }, and get-newtab-token-css.mjs emits a base block plus a@media (forced-colors)one, both unlayered. The desktop path in get-token-css.mjs emits@layer tokens-prefers-contrast { @media (prefers-contrast) { … } }— the pattern the design token docs specify. about:newtab does load the toolkit sheets (prerendered/activity-stream.html linkstokens-brand.css, which@importstokens-shared.css), so the 43-tokentokens-prefers-contrastlayer is present in the document — the unlayered:root.nova-tokensblock simply outranks it, shadowing 29 of those tokens. -
Base accessibility values are dropped when a nova override exists. In the same file,
originalValueis replaced by the nova value object, sooriginalValue.forcedColorsis undefined and nothing falls back to the base token. panel.tokens.json declares"forcedColors": "Menu"while panel.nova.tokens.json declares onlynativeTheme/default— that is the--panel-background-colorcase, and the other three clobbered under forced-colors. The desktop formatter survives this because its output is layered so the base layers still apply; the shim, unlayered and self-contained, loses them outright.
Proposed fix — generator only, then regenerate with mach buildtokens:
get-newtab-tokens-by-layer.mjs: add aprefersContrastbucket mirroringforcedColors, and fall back to the basetoken.original.value'sprefersContrast/forcedColorswhen the nova override object does not define one.get-newtab-token-css.mjs: emit@media (prefers-contrast) { :root.nova-tokens { … } }ahead of the forced-colors block, and wrap all three blocks in thetokens-foundation-nova/tokens-prefers-contrast-nova/tokens-forced-colors-novalayers already ordered intokens-shared.css, so the shim can no longer outrank the toolkit's accessibility layers. Worth confirming the layer names resolve as intended givenactivity-stream.cssloads aftertokens-brand.css.
Both halves are needed: the 3 tokens-prefers-contrast-nova overrides sit behind @media -moz-pref("browser.nova.enabled"), which newtab does not set (it gates on browser.newtabpage.activity-stream.nova.enabled), so a layer wrap alone will not recover those — emitting the block is what covers them. Conversely the layer wrap is what fixes (2).
Verification anchor: tests/try-runner.js rebuilds every token target with the real config. Since this changes how all New Tab surfaces render under HCM, an a11y review of the resulting palette is advisable — see HCMMediaQueries.
This is reasoned from the source; I did not build or run it.
Suggested severity: S3
Defeats a high-contrast accommodation across every New Tab surface on Linux and macOS with no in-product workaround, but the page stays legible under the default Nova palette, and users with a hard HCM requirement generally trigger forced-colors, which the shim already covers apart from four tokens.
If you'd like to provide feedback on this comment, please use the 👍 or 👎 reaction.
If you want to categorize your feedback you can add one of the following tags: ai-triage-wrong-file, ai-triage-wrong-cause, ai-triage-hallucination, ai-triage-out-of-scope, ai-triage-wrong-fix, ai-triage-shallow-fix.
Updated•1 month ago
|
| Assignee | ||
Comment 2•1 month ago
|
||
Every declaration in the generated _tokens.scss is re-indented, so the only substantive change there is the new prefers-contrast block.
Updated•1 month ago
|
| Assignee | ||
Comment 3•1 month ago
|
||
Updated•1 month ago
|
Comment 4•28 days ago
|
||
The severity field for this bug is set to S3. However, the accessibility severity is higher, .
:dao, could you consider increasing the severity?
For more information, please visit BugBot documentation.
| Assignee | ||
Updated•25 days ago
|
Comment 6•25 days ago
|
||
Not a blocker but nice to fix for the experiment in 157.
https://hg.mozilla.org/mozilla-central/rev/a0073190ff82
https://hg.mozilla.org/mozilla-central/rev/4b7346c10a47
Comment 8•24 days ago
|
||
The patch landed in nightly and beta is affected.
:dao, is this bug important enough to require an uplift?
- If yes, please nominate the patch for beta approval.
- See https://wiki.mozilla.org/Release_Management/Requesting_an_Uplift for documentation on how to request an uplift.
- If no, please set
status-firefox157towontfix.
For more information, please visit BugBot documentation.
| Assignee | ||
Updated•15 days ago
|
Updated•12 days ago
|
Reproducible on a 2026-09-04 Firefox Nightly build on Ubuntu 22.
Verified as fixed on Firefox Nightly 158.0a1 on Ubuntu 22 and macOS 13.
Description
•