Open fdelapena opened 1 month ago
Interesting scenario. Thanks for raising this. You're right that axe is assuming the background is white. The difficulty here is that the computed background color for the HTML element will be transparent, regardless of the color-scheme. There are ways to figure out which contrast mode is used, like inject a text with a contrast filter on it, that's going to trigger DOM observer events, which can have unforeseen consequences.
@fdelapena have you seen this cause false positives on a live site? If so it would be nice to have that as an example to go with the issue.
We could have an option you pass into analyze to specify the mode to be used for this default instead of white always.
also, this might work
const isDarkMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
Reminder for ourselves that if we do use something like media query + color-scheme to infer a page canvas background color, that color-scheme can be specified in meta tags as well as CSS.
I think the bigger difficulty than determining which color scheme is in play might actually be determining which exact background color we should use for the color scheme. UAs in practice all use different values for their dark mode background canvas color. Today on the same machine/monitor, I see #121212 in Chrome, #1E1E1E in Safari, and #1C1C22 in Firefox. It gets more complicated still if we also want to extend that support to forced color modes. Anyone have any bright ideas for querying the color directly?
This is similar to https://github.com/dequelabs/axe-core/issues/3605
This feels close to something that could work, but unfortunately it just resolves the default values of the system colors, not the system color values adjusted for UA settings and page color-scheme :(
function getCanvasColor(doc) {
const canvasEl = doc.createElement('canvas')
const ctx = canvasEl.getContext('2d')
ctx.fillStyle = 'Canvas'
return ctx.fillStyle // in chrome, returns '#ffffff' regardless of color scheme
}
@fdelapena have you seen this cause false positives on a live site? If so it would be nice to have that as an example to go with the issue.
Yes, it is currently live at https://abierta.cr/ , hope it helps.
Note that the site currently has a strict header-based policy that could prevent some JavaScript tests without using extensions to circumvent them.
...have you seen this cause false positives on a live site? If so it would be nice to have that as an example to go with the issue.
This creates false positives with any document that doesn't override the default background color and link color in chrome with the default stylesheet... which is a few sites
An alternative to @dbjorge's approach which will evaluate in the context of the page, is to set the html element's background to Canvas
if it's not overridden, or alternatively to do something similar but with an element inserted into the document.
function getCanvasColor(doc) {
const el = doc.createElement('div');
div.style.display = 'none';
div.style.backgroundColor = 'Canvas';
document.firstElementChild.appendChild(el);
const color = getComputedStyle(el).backgroundColor;
el.remove();
return color;
}
But obviously this adds DOM, which is clearly not what axe would like to do. Another option is to temporarily style the root with background: Canvas
, measure it, and then set it back to whatever it was.
Product
axe-core
Product Version
4.10.0
Latest Version
Issue Description
Expectation
The report passes without getting insufficient contrast in
a
element when using dark color-scheme.Actual
The report says the background color is #ffffff when it is likely #000000. The foreground color is calculated as
#9e9eff
. Additionally, the contrast filter seems to be ignored, where the link foreground should be calculated somehow close to#ffffff
.How to Reproduce
Set the system to dark mode. Crate a page with the following HTML and CSS and test it with DevTools axe extension (tested with 4.92.0) or Lighthouse (provided with Chromium):
Additional context
Tested under latest Chromium on GNOME.