The report is four words long. "Which one is selected?" They attach a screenshot and every tab looks identical. On your machine the selected tab carries a soft gradient and a shadow lifting it off the row, and it is unmissable.
Nothing in your CSS is wrong. It was overruled before it painted.
The name everybody uses for this is wrong
Windows calls it High Contrast Mode, and so does most of what is written about it. The CSS specifications deliberately do not. The media feature is forced-colors, its values are none | active, and Media Queries 5 says of active: "This does not necessarily indicate a preference for more contrast."
That is not pedantry, it is the bug. CSS Color Adjustment notes that users "can also customize their own themes, for example to provide low contrast or hue contrast." So the affected population is not "people who want black on white". It is everybody who has handed colour control to their operating system, for any reason, running themes that look nothing like the one you would think to test.
What actually happens to your stylesheet
With forced colors mode active, the colour components of a long list of properties are forced to the user's palette: color, background-color, border-color, outline-color, caret-color, accent-color, fill, stroke, text-decoration-color, scrollbar-color and more. Only system colours survive.
Recolouring is the part people expect. These three are the part they do not, and all three are normative:
-
box-shadowandtext-shadowcompute tonone. Not recoloured. Removed. -
background-imagecomputes tononeunless the original value contains aurl()function. Your gradient is gone. An actual image file stays. -
For
background-color, the alpha channel is taken from the original value, so transparent stays transparent.border: 1px solid transparent, the usual trick for reserving layout space, keeps its transparency, while every border you did colour becomes a visible system colour.
Now re-read the selected tab. The gradient computed to none, the shadow computed to none, and the one difference left over was a colour forced to the same system colour as its neighbours. Three independent signals, every one of them the same signal.
The focus ring version of the same thing
A focus ring drawn with box-shadow disappears. A focus ring drawn with outline does not: outline-color is on the forced list, so it is recoloured and still painted. Identical in your browser, opposite on theirs.
Inline SVG behaves differently again, and on purpose. The user agent stylesheet sets forced-color-adjust: preserve-parent-color on svg, so fill: currentColor follows the forced text colour, while a hard-coded hex fill keeps a colour the user's theme never agreed to.
Why your own diagnostics agree with you
This is the part that matters when you are debugging from a distance. The specification draws a line between the computed value and the used value, and the forcing happens at the used value:
The computed value for
colorwill be a 50-50 blend of theCanvasTextandCanvassystem colors. That value will inherit to descendants and be observable via APIs such ascomputedStyleMap(). The used value forcolorwill be a system color chosen by the UA.
So getComputedStyle hands you back your own colour. Any self-diagnostic you ship, any "paste your computed styles" request, any snapshot assembled from the CSSOM reports the page you wrote rather than the page that rendered. The two disagree, and only one of them is on screen.
And the reporter cannot tell you
This is an operating system theme. Not a browser setting, not per-site, with no banner reminding anybody it is on. They enabled it once, possibly years ago, for a reason that has nothing to do with you, and every application on that machine has looked like that ever since. It is not a fact about your software, so it does not occur to them to mention it, for the same reason nobody volunteers their screen resolution.
One line turns it into a measured field instead of a question nobody thinks to ask:
matchMedia("(forced-colors: active)").matches
Put it wherever your bug form already collects the user agent. It costs nothing, it is true at the moment the report is written, and it separates "your CSS is broken" from "your CSS never ran" before somebody spends an afternoon failing to reproduce it.
Top comments (1)
For icon-only tabs, pair
aria-selectedwith a visible border indicator.currentColoralone won't distinguish selected icons when forced colors flatten the palette.