Now that the standardized <meta name="color-scheme"> and the corresponding CSS property color-scheme have landed in Chrome and Safari, an accessibility issue around link colors occurs:
The colors defined in §14.3.4 Phrasing content…
:link { color: #0000EE; }
:visited { color: #551A8B; }
:link:active, :visited:active { color: #FF0000; }
:link, :visited { text-decoration: underline; cursor: pointer; }
…do not have sufficient contrast on a dark background. See this demo (note the [Top] links):

This issue should probably also affect the definition of the CSS System Colors:
LinkText (contrast insufficient): Text in non-active, non-visited links.VisitedText (contrast insufficient): Text in visited links.ActiveText (contrast OK-ish): Text in active links.I have also opened bugs for Chrome, WebKit, and Firefox for awareness and to get this fixed.
cc @whatwg/a11y @whatwg/css
Other colors used in the spec's Rendering section
https://html.spec.whatwg.org/multipage/rendering.html#flow-content-3
dialog {
...
background: white;
color: black;
}
https://html.spec.whatwg.org/multipage/rendering.html#phrasing-content-3
mark { background: yellow; color: black; } /* this color is just a suggestion and can be changed based on implementation feedback */
https://html.spec.whatwg.org/multipage/rendering.html#tables-2
table[rules=none i], table[rules=groups i], table[rules=rows i],
table[rules=cols i], ...... {
border-color: black;
}
https://html.spec.whatwg.org/multipage/rendering.html#the-hr-element-2
hr {
color: gray;
border-style: inset;
...
}
https://html.spec.whatwg.org/multipage/rendering.html#phrasing-content-3
The initial value for the 'color' property is expected to be black. The initial value for the 'background-color' property is expected to be 'transparent'. The canvas's background is expected to be white.
I'm a little confused by this issue. Could you provide more background?
In particular, does using one of the features mentioned in the OP automatically change the html/body element's background? The links don't go to specs, but instead to issues with problem statements, so I can't really tell.
I'm also wondering if this is a general problem whenever authors use CSS/HTML features to change their page's background. Or is it specific to these particular features in some way?
I'm a little confused by this issue. Could you provide more background?
In particular, does using one of the features mentioned in the OP automatically change the html/body element's background? The links don't go to specs, but instead to issues with problem statements, so I can't really tell.
The spec for this feature is here. I have described color-scheme in an article (this is a staging link, please don't circulate it).
I'm also wondering if this is a general problem whenever authors use CSS/HTML features to change their page's background. Or is it specific to these particular features in some way?
This is only an issue with the default user agent stylesheet rendering, that is, without any author-provided CSS. Note that the demo is completely CSS-free.
When an author changes the page background themselves, it's up to them to make sure the contrast is sufficient.
Sorry, I'm still confused. The spec you link to is for a CSS property and meta tag, so presumably the author must be using a CSS property or meta tag to change the page background? Or no?
The demo is completely CSS free, but also does not contain a meta tag, and does not "toggle between dark and light every three seconds" (even on Chrome Canary with experimental web platform features enabled). So I am unsure what it is meant to illustrate. (Edit: I see now that the demo is not completely CSS free after all, but instead is setting an inline style="" on the HTML element? At least in my browser that style has no effect though.)
The spec you link to is for a CSS property and meta tag, so presumably the author must be using a CSS property or meta tag to change the page background? Or no?
Correct. But if you say color-scheme: dark (either via CSS or via meta tag), you opt in your browser to UA stylesheet optimizations for dark mode. Try the demo on Safari; in Chrome, we're still working on improving form elements rendering etc.
The demo is completely CSS free, but also does not contain a meta tag, and does not "toggle between dark and light every three seconds" (even on Chrome Canary with experimental web platform features enabled). So I am unsure what it is meant to illustrate.
The demo inserts the CSS property dynamically and toggles its value. There is no other CSS apart from that.
In Chrome, you need to switch your OS to dark mode for the demo to have an effect (I have pinged @lilles to see if this is the correct behavior). Again try the demo on Safari; there, it works independent from the OS theme.
I see. So then I am confused why we would adjust the default rendering of, e.g., links, when the page changes their background using color-scheme: dark, but not when the page changes their background using background: black. They seem the same to me.
The difference is the following:
/**
The site supports dark theme. Dear UA stylesheet,
please handle everything I haven't handled. And
since the one rule below is my only CSS, handle it all.
*/
:root {
color-scheme: dark;
}
versus:
/**
The site supports dark and light theme. Dear UA stylesheet,
please handle everything I haven't handled. And
since I handle link colors, handle everything else.
*/
:root {
color-scheme: dark light;
}
a {
/* I know what I'm doing, I mess with the default styling */
color: white;
background-color: black;
}
@media (prefers-color-scheme: dark) {
a {
/* I know what I'm doing, I mess with the default styling */
color: black;
background-color: white;
}
}
Yes, switching on the color scheme is assumed to switch all the "default" coloring as well. The color-scheme property is not a "make this dark" command, but an "I'm okay with making this dark, feel free to do so if the user wants" hint. (Without it, the page remains in standard "light" mode even if the user has their OS set to dark mode, for backwards compatibility.)
When the UA flips into dark mode, the default background and text color change, as do the colors of inputs. Links should follow along, as should any other default colors applied by the UA stylesheet.
Two reasonable ways to approach this.
The first, and simplest, is to switch as much of these colors as possible to using the allowed system color keywords, which work not only with light/dark mode, but with forced-colors mode as well. As long as these keywords are only used in the properties with special resolved-value behavior, then it shouldn't even be a detectable change; calling getComputedStyle() will still give you the rgba color, not the keyword. (But any other color usage will expose the keyword, so I'd have to review the list of properties used.)
The second way is to explicitly add an @media (prefers-color-scheme: dark) {...} block to the HTML UA stylesheet, setting the colors appropriately for dark mode.
If there are properties not on the resolved-values list, we can do option 2 for just those, and rely on option 1 for the rest for simplicity; or we could do option 2 for everything for consistency. I have no opinion on the matter.
To me, Option 1 sounds like the more consistent and more scalable approach; more scalable especially given the other color adjustments forced-color-adjust and color-adjust (and potentially future others, who knows). System colors (theoretically at least) need to be defined only once on the system level, and every app can then make use of them.
Ideally that would have been done as part of standardizing color-scheme. It doesn't seem like system colors cover all our use cases (e.g., mark or dialog) and it also seems like there might be unintentional side effects there, depending on how they are implemented.
cc @smfr
For <mark>, there could be new system colors MarkText and Mark. FWIW, purely in the context of dark mode (but probably also OK in high contrast scenarios): the current yellow on black we have in Chrome, Firefox, and Safari seems to work fine universally. Probably still better to have a system colors pair.
For <dialog>, Chrome at least doesn't seem to do anything special (apart from the backdrop that might need adjustment).

Chrome with manually injected <meta name="color-scheme" content="dark"> ⤴
It's early days for <dialog> in Firefox and Safari, but from enabling the features manually, they both seem to use Canvas and CanvasText.

Safari with manually injected <meta name="color-scheme" content="dark"> ⤴

Firefox (doesn't support color-scheme yet) ⤴
Yes, if we need to we can add more system colors; if they're needed just to express the default UA visual semantics, that's a good argument for their inclusion.
But also you can just use the MQ to manually address those particular color needs explicitly, and use the system colors for everything else for simplicity.
But also you can just use the MQ to manually address those particular color needs explicitly, and use the system colors for everything else for simplicity.
(I read this as concerning developer-provided CSS, not as using the MQ in the user-agent stylesheet.)
If the out-of-the box user-agent stylesheet experience is not accessible, I don't think this can be the solution.
No question, most developers will override the default look and feel and have link colors that are on-brand etc., but also some won't. Prominent timely example: http://lite.cnn.com/en (you can see all their CSS in the screenshot, I have inserted the meta tag manually):

No, Tab meant in the UA stylesheet.
I do think that if we were to switch to system colors their light/dark defaults would have to be written down somewhere.
No, Tab meant in the UA stylesheet.
Gotcha, I wasn't 100% sure, so I added my (wrong) interpretation. In that case, sure, MQing in the UA stylesheet is an option, following the nomenclature from above, that'd be Option 2. Personally, I still prefer Option 1.
I do think that if we were to switch to system colors their light/dark defaults would have to be written down somewhere.
+1.
I do think that if we were to switch to system colors their light/dark defaults would have to be written down somewhere.
You mean if we start using LinkText, VisitedText, ActiveText in the UA sheet we need to spec the exact RGBA values for both light and dark versions, e.g. in CSS Color?
Wrt @media queries in the UA stylesheet, that won't work since the media query depends on the preferred color-scheme and the UA colors could be different for different elements in the same document since the color-scheme property has a per element computed and used value. If the preferred color scheme is dark, the two links below would be rendered with different colors (with system colors in the UA sheet):
<a href="link.html" style="color-scheme: dark light">Link 1</a>
<a href="link.html" style="color-scheme: light">Link 2</a>
But this UA sheet would end up with orange for both:
@media (prefers-color-scheme: dark) { a:link { color: orange } }
@media (prefers-color-scheme: light) { a:link { color: blue } }
@lilles yeah, exactly. I guess it's an existing problem that it's not defined what getComputedStyle() returns for (default) system colors and this adds to that.
It sounds like CSS needs to define system colors for all the different colors used in HTML's Rendering section and define their default values for various color schemes.
just wanted to check...am i missing something fundamental? if i have a vanilla HTML document with no styling defined, load it in Chrome, and switch (on Windows) between light/dark app mode, I see Chrome's UI change, but the vanilla page itself does not change at all (using Chrome 80)
and to clarify, i know that i as an author can then go in and make prefers-color-scheme changes specifically, but at that point i would not expect the UA to magically handle things/change styles for me, as the UA wouldn't know WHAT specific changes I made - other than perhaps assuming i made the backgrounds dark. but what if i didn't? what if i explicitly defined my author styles to remain light even in that scenario, would i THEN have to fight against the UA's assumption?
[edit: ah, seems i got the wrong end of the stick here ... so this is explicitly about when the page opts into dark mode via the meta, rather than adapting to user preference?]
@patrickhlauke https://drafts.csswg.org/css-color-adjust/#color-scheme-prop
@patrickhlauke To quickly test this, go to https://lite.cnn.com/en, then paste the snippet below in the console:
document.head.innerHTML += '<meta name="color-scheme" content="dark">'
Yup, backwards compat constrains what we can do by default; too many pages are authored with the assumption of a white background or black text, and would become unreadable if swapped to a dark background or light text. By default, the only result of your OS being in dark mode is that the (prefers-color-scheme: dark) MQ now matches, so you can manually adjust all of your colors as desired.
To opt your page into UA-provided dark-mode colors, the color-scheme property (or <meta> value) must be used, as @annevk links to.
yeah, sorry for coming in sideways there...took me a few re-reads, but i get it now and agree.
https://github.com/w3c/csswg-drafts/issues/4924 now has introduced more system color keywords.
Are defaults defined for various color schemes? (Doesn't look like it, so this isn't unblocked yet.)
Not yet, @fantasai and I ran out of time to address that in our last working day. We'll get to it soon.
Most helpful comment
Yes, switching on the color scheme is assumed to switch all the "default" coloring as well. The
color-schemeproperty is not a "make this dark" command, but an "I'm okay with making this dark, feel free to do so if the user wants" hint. (Without it, the page remains in standard "light" mode even if the user has their OS set to dark mode, for backwards compatibility.)When the UA flips into dark mode, the default background and text color change, as do the colors of inputs. Links should follow along, as should any other default colors applied by the UA stylesheet.
Two reasonable ways to approach this.
The first, and simplest, is to switch as much of these colors as possible to using the allowed system color keywords, which work not only with light/dark mode, but with forced-colors mode as well. As long as these keywords are only used in the properties with special resolved-value behavior, then it shouldn't even be a detectable change; calling
getComputedStyle()will still give you the rgba color, not the keyword. (But any other color usage will expose the keyword, so I'd have to review the list of properties used.)The second way is to explicitly add an
@media (prefers-color-scheme: dark) {...}block to the HTML UA stylesheet, setting the colors appropriately for dark mode.If there are properties not on the resolved-values list, we can do option 2 for just those, and rely on option 1 for the rest for simplicity; or we could do option 2 for everything for consistency. I have no opinion on the matter.