Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Color contrast miscalculated due to dark color-scheme background misinterpreted as #ffffff #4608

Open
1 task done
fdelapena opened this issue Oct 11, 2024 · 8 comments
Open
1 task done
Labels
color contrast Color contrast issues fix Bug fixes
Milestone

Comments

@fdelapena
Copy link

Product

axe-core

Product Version

4.10.0

Latest Version

  • I have tested the issue with the latest version of the product

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):

<doctype html>
<html lang=en>
<meta charset=utf-8>
<meta name=description content="Some test">
<title>Test</title>
<p>Some <a href=//example.org>link example</a>.
html {
	color-scheme: light dark;
}

/* optional, secondary issue, seems to be ignored in results as well */
a {
	filter: contrast(10);
}

Additional context

Tested under latest Chromium on GNOME.

@fdelapena fdelapena added the ungroomed Ticket needs a maintainer to prioritize and label label Oct 11, 2024
@WilcoFiers
Copy link
Contributor

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.

@WilcoFiers WilcoFiers added fix Bug fixes color contrast Color contrast issues and removed ungroomed Ticket needs a maintainer to prioritize and label labels Oct 11, 2024
@WilcoFiers WilcoFiers added this to the Axe-core 4.11 milestone Oct 11, 2024
@dylanb
Copy link
Contributor

dylanb commented Oct 11, 2024

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;

@dbjorge
Copy link
Contributor

dbjorge commented Oct 11, 2024

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?

@straker
Copy link
Contributor

straker commented Oct 15, 2024

This is similar to #3605

@dbjorge
Copy link
Contributor

dbjorge commented Oct 15, 2024

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
Copy link
Author

fdelapena commented Oct 16, 2024

@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.

@xorgy
Copy link

xorgy commented Oct 17, 2024

...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

@xorgy
Copy link

xorgy commented Oct 17, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
color contrast Color contrast issues fix Bug fixes
Projects
None yet
Development

No branches or pull requests

6 participants