w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.52k stars 673 forks source link

[css-ui-4] choosing background colors for accent-color for contrast #6159

Closed josepharhar closed 3 years ago

josepharhar commented 3 years ago

accent-color allows the page to specify a color to be drawn sort of in the foreground of several form controls, but does not specify anything about what color the browser should draw the rest of the form control with.

When I was implementing this in chromium, I realized that I needed to draw the rest of the background of the form control in a color that had enough contrast to the accent-color in order to make it easy to see the accent-colored parts. I made a basic solution to this in chromium by looking at the "relative luminance" of the accent-color and using that to decide if the accent-color was light or dark, and then drawing the rest of the control as if it were in color-scheme:light or color-scheme:dark based on that.

Should any of this behavior be specified? Should there be any guidance on how to color the rest of the form control in response to the accent-color? Does anyone have any feelings about the current implementation which you can try out in chrome canary, such as tweaking the point where it switches from light to dark or finding some way to make it have a range of background colors instead of just two?

Some more context here: https://bugs.chromium.org/p/chromium/issues/detail?id=1189332 Example site for testing: https://css-accent-color.glitch.me/

cc @mfreed7 @fantasai @argyleink

svgeesus commented 3 years ago

First, props for correctly undoing gamma-encoding when calculating relative luminance (many get this wrong).

In terms of the crossover point, it may be helpful to know that lab(50% 0 0) is color(xyz 0.177596 0.184187 0.151993) in other words a CIE Lightness of 50% (visually mid way between white and black) is a luminance (Y) of 0.184.

emilio commented 3 years ago

I know we discussed this earlier, but I think it'd be best if we force the author to give two colors instead of trying to magically do stuff.

We do something similar with the OS accent color in Gecko for the new form controls, using the relative luminance to compute lighter / darker colors from the OS accent: https://searchfox.org/mozilla-central/rev/74d0efd1107a26f178b108b6a18a179e9b06547c/widget/nsNativeBasicTheme.cpp#136-165

However we do have a known good pair of foreground / background colors provided by the OS, which ensure that we don't mess up contrast.

argyleink commented 3 years ago

there's conflict with auto choosing a background with color-scheme too. like, i can specify a dark color scheme preference, get dark controls, then pick an accent color which turns all the controls light.. which feels like i'm in the middle of a game of wack-a-mole.

there's also color-contrast() in Color 5 that seems handy here, for Joey and developers?

maybe a simpler route is better here? less magic like @emilio is saying. could spend all this time trying to write algo's which keep form controls within proper contrast, then developers make all labels and paragraphs white on white with color and background css. I understand the original intent here, to force prevent low contrast controls, but maybe it's over-reaching? i dont think it's intuitive to tell someone: "you can use your brand color as form control accent colors now! but, beware, the color you choose may flip the controls to a light or dark theme." seems obvious i have a new responsibility once i start styling form controls different then their defaults?

🙂

tabatkins commented 3 years ago

I know we discussed this earlier, but I think it'd be best if we force the author to give two colors instead of trying to magically do stuff.

There can be more than two colors used in the control, tho, so this still wouldn't solve everything; magic will always be required unless we explicitly specify what set of colors are allowed to be used on controls.

Should any of this behavior be specified? Should there be any guidance on how to color the rest of the form control in response to the accent-color?

Happy to provide more non-normative guidance, so engineers don't have to reinvent the wheel here on their own. Basing it on relative luminance sounds completely reasonable, tho I'd want to do some testing to see how it responds in practice. I'll see if I can get Canary working again on this machine to try out your impl. ^_^

emilio commented 3 years ago

There can be more than two colors used in the control, tho, so this still wouldn't solve everything; magic will always be required unless we explicitly specify what set of colors are allowed to be used on controls.

True, but there's usually a need to have some sort of background and foreground color. The rest of the colors are mostly decorative. Asking the author for two colors ensures there can be contrast when the engine deems it necessary.

fantasai commented 3 years ago

We've got https://github.com/w3c/csswg-drafts/issues/5544 open on providing multiple alternative accent colors to be chosen by optimizing contrast. But I don't think we need to force the author to give more than one.

Agree with Tab that we can add non-normative suggestions e.g. on what math to use to calculate or adjust contrast, but I would be against adding any kind of normative rules: this is an area where UAs should be allowed to freely experiment.

svgeesus commented 3 years ago

@emilio wrote

We do something similar with the OS accent color in Gecko for the new form controls, using the relative luminance to compute lighter / darker color

I would be interested to know about these magic numbers

  constexpr float kLightLuminanceScale = 25.048f / 13.693f;
  constexpr float kDarkLuminanceScale = 9.338f / 13.693f;
  constexpr float kDarkerLuminanceScale = 5.901f / 13.693f;
josepharhar commented 3 years ago

I would be interested to know about these magic numbers

What I currently have implemented in chrome is a check to see if the relative luminance is less than 0.5, which is sort of a magic number that I imagine will be adjusted unless we decide to do something really different here. There is some similar chrome UI code which has a separate magic number. I don't know how it was selected, and I could see myself reusing it...

svgeesus commented 3 years ago

@josepharhar thanks for the pointer.

A relative luminance of 0.5 is no-where near the middle of the lightness scale, though, if that is what you were looking for. (A CIE Lightness of 50% is in the middle).

lab(50% 0 0) is color(xyz 0.1776 0.18419 0.15199) is rgb(46.637% 46.633% 46.627%) so the relative luminance (the Y component) is 0.18419

lab(76.07% 0 0) is color(xyz 0.48212 0.50001 0.41261) is rgb(73.542% 73.536% 73.528%) so much lighter; here the relative luminance is 0.5

svgeesus commented 3 years ago

I can get close to that other magic number, lab(53.135% 0 0) is color(xyz 0.20412 0.2117 0.1747) so reative luminance 0.2117.

I don't understand the comment about kGoogleGrey900, either

But is is certainly a better threshold than a relative luminance of 0.5.

josepharhar commented 3 years ago

maybe a simpler route is better here? less magic like @emilio is saying. could spend all this time trying to write algo's which keep form controls within proper contrast, then developers make all labels and paragraphs white on white with color and background css. I understand the original intent here, to force prevent low contrast controls, but maybe it's over-reaching? i dont think it's intuitive to tell someone: "you can use your brand color as form control accent colors now! but, beware, the color you choose may flip the controls to a light or dark theme." seems obvious i have a new responsibility once i start styling form controls different then their defaults?

Perhaps would it make sense to instead of having the browser decide to color the rest of the control dark or light, let the page specify color-scheme:dark or color-scheme:light? And then we add a DevTools console message or add something to the DevTools styles sidebar to say when the combination of color-scheme and accent-color doesn't have enough contrast?

Maybe that's not how color-scheme should be used since it can just be changed dynamically by the OS...

emilio commented 3 years ago

I would be interested to know about these magic numbers

They're not magic. We have a "canonical" color scheme (a few lines above), the one you get on Windows or with widget.non-native-theme.use-theme-accent=false.

Those numbers are just the luminance of the light / dark / darker colors in the canonical color scheme (25.04791, 9.33808, and 5.90106% respectively) divided by the luminance of the regular accent color (13.693%). So we scale the luminance of the accent color by similar amounts to achieve similar looks with different accent colors. We use a similar trick to auto-darken scrollbars too.

emilio commented 3 years ago

So I did a prototype of this on Firefox and it suffers from the same issue, depending on whether you consider the color "dark", I choose a white or black foreground color, and that just creates very weird contrast in some colors which aren't too dark nor too light, and the choice of white or black seems pretty arbitrary.

So I'm pretty sure that it'd be better if we allowed authors to provide a "foreground" color of sorts. I also think that we don't want to auto-switch to dark-mode form controls, which is different from that IMO.

josepharhar commented 3 years ago

I just re-read the spec, and I noticed this part:

The UA must maintain contrast for legibility of the control, and in order to do so may adjust the luminance or brightness of the color or make color substitutions in other parts of the control (e.g. switching an overlaid glyph from using color to using background-color). It may also generate variations of the color for gradients etc. to match the control to platform conventions for the use of the accent color.

This seems to suggest that not only the colors used in other parts of the control can be changed, but also the accent-color itself...?

Also, I made a gif that better demonstrates what I currently implemented in chrome (I haven't tweaked anything since starting this discussion): accentcolor

josepharhar commented 3 years ago

I recently updated the behavior in chrome to determine when the color-scheme gets flipped to look at the contrast ratio of the adjacent color used when painting each control. However, in the interest of interop, maybe it would be better if we decided on something else...

We've got #5544 open on providing multiple alternative accent colors to be chosen by optimizing contrast. But I don't think we need to force the author to give more than one.

I skimmed the issue and it's a bit mind boggling for me to figure it all out, but since we aren't forcing the author to give more than one, I'm going to focus on making this work with the single option case.

So I'm pretty sure that it'd be better if we allowed authors to provide a "foreground" color of sorts. I also think that we don't want to auto-switch to dark-mode form controls, which is different from that IMO.

@tabatkins and @fantasai seem to be against providing multiple colors for foreground and background based on their previous comments in this thread...?

Happy to provide more non-normative guidance, so engineers don't have to reinvent the wheel here on their own. Basing it on relative luminance sounds completely reasonable, tho I'd want to do some testing to see how it responds in practice.

Agree with Tab that we can add non-normative suggestions e.g. on what math to use to calculate or adjust contrast, but I would be against adding any kind of normative rules: this is an area where UAs should be allowed to freely experiment.

@tabatkins @fantasai could I get some suggestions on what to do with the rest of the control in response to the accent-color? Do you think that flipping the color-scheme is a good idea or a bad idea? Are there any alternatives? Is my current contrast ratio check of 3 too aggressive? Should I change it back to a luminance check?

i dont think it's intuitive to tell someone: "you can use your brand color as form control accent colors now! but, beware, the color you choose may flip the controls to a light or dark theme." seems obvious i have a new responsibility once i start styling form controls different then their defaults?

Another way I could see this playing out is where authors (must?) write two accent-color rules based on the color scheme like this:

@media (prefers-color-scheme: dark) {
  input {
    accent-color: lightblue;
  }
}
@media (prefers-color-scheme: light) {
  input {
    accent-color: darkblue;
  }
}
josepharhar commented 3 years ago

Responding to @emilio's comments from my intent to ship:

So the way form controls are drawn on Firefox requires two colors, a "background" color (the accent color), and a "foreground" color (a color that has sufficient contrast with the accent color). All other decorative colors are derived from the accent color, by tweaking the luminance.

For native form controls, the foreground and background colors are provided by the OS (the macOS accent color, the Linux theme accent color, etc). On Windows and Android it's hard-coded to white-on-blue, though you can use the OS accent color if you change widget.non-native-theme.use-theme-accent to true).

For the accent-color property, as specified it only requires one color (the accent color), so we just choose a white or black foreground depending on whether the color is "dark enough":

https://searchfox.org/mozilla-central/rev/2c991232499e826e46f9d976eb653817340ba389/widget/nsNativeBasicTheme.cpp#192-197

Note that we always blend the accent color with white to make sure it's opaque.

Anyhow, I think the current approach is not great, but is as good as it can get with only one color. I think it's slightly unfortunate as some accent colors would still look better with white, and the authors could want e.g., a checkmark that isn't white or black. That's why I think the option of providing two colors (background and foreground) to the property is best.

I see why specifying a foreground and background color makes sense for firefox, but in chromium we have a bunch of hard coded light scheme colors and dark scheme colors. I presume that all of these were hand picked by UX people as opposed to being generated based on relative luminance... I suppose if the relative luminance foreground/background thing is something we should be doing instead when accent-color is present, then we could back-calculate the relative luminance of these dozens of colors to try to make something that resembles firefox, but it sounds rather complicated and I wonder if it would end up better than my current forced-color-scheme-when-needed implementation.

josepharhar commented 3 years ago

I made a test page with many checkbox accent-colors and compared the output with firefox nightly, chrome before my new contrast ratio patch, and chrome after my contrast ratio patch:

Firefox Nightly

Screen Shot 2021-06-10 at 12 06 47 PM

Chrome before new contrast patch

Screen Shot 2021-06-10 at 12 07 20 PM

Chrome after new contrast patch

Screen Shot 2021-06-10 at 12 07 27 PM

josepharhar commented 3 years ago

With the idea in mind of removing the harsh transition between light and dark themes, I decided to try generating the checkmark color based on whatever grayscale color has exactly the desired contrast ratio, and I ended up with these. This is not the current behavior in chromium like my last comment, this was just an experiment. I feel like they simply suggest that we should be using a black checkmark in most cases though...

3.0 contrast ratio ![3](https://user-images.githubusercontent.com/7681467/122604615-14703080-d02b-11eb-9389-1f2a32758dd8.png)
4.0 contrast ratio ![4](https://user-images.githubusercontent.com/7681467/122604626-19cd7b00-d02b-11eb-972f-cf8251412754.png)
fantasai commented 3 years ago

@tabatkins and @fantasai seem to be against providing multiple colors for foreground and background based on their previous comments in this thread...?

I am, yes. I think if you want more information than just accent-color, some combination of color and color-scheme and maybe also background-color (of either the element or the canvas) should give enough information to do something that coordinates with the page. The use of colors varies a lot in form controls (across controls, across platforms, and across time), checkboxes being one of the simplest and most consistent. We know we're not going to be able to ask the author for a full, exact palette for every control, so we need to accept that the author can only give us hints rather than instructions here.

There's some cases where contrast will require a light color or a dark color, but in the middle zone there's a lot of leeway. Which way to bias might want to take into consideration the color-scheme (as you've done in the updated Chrome patch) but also things like “is the checkmark in our design system intended to coordinate with the background color or the foreground color of the theme” which is going to vary based on UA- and platform-specific design choices. So we can't dictate that in the spec.

The only thing we're going to dictate, is that the UA does its best to ensure some reasonable level of legibility. (It doesn't have to maximize contrast.)

As for pages that use tinted foregrounds/background colors, you can check color and/or background-color to see if either creates enough contrast to use in place of the system default colors. A page with dark brown text, a tan background, and light green accent-color for example, might want dark brown or tan checkmarks instead of black or white ones.

Remember the point of accent-color isn't to give 100% control over the checkboxes to the author. It's to let them influence the colors of the form control scheme designed by the UA. In other words, its parameterizing the design logic that led to the default colors, not dictating the final colors.

josepharhar commented 3 years ago

I propose that we leave the spec as-is and close this issue.

Relative to when I opened this issue, I now have an implementation that I am confident in and I believe makes sense. In the scheme of things, I think that the firefox implementation is pretty similar to chrome's since we are both flipping the color of the checkmark between light and dark. If firefox wishes to improve compat by unifying the breaking point where we flip the color of the checkmark, I am happy to discuss and possibly adjust the point at which we flip the checkmark in chrome, even after shipping. I don't feel confident that we can go back and change the spec to allow multiple colors due to the arguments provided in this thread.

josepharhar commented 3 years ago

Based on the lack of recent feedback, and the canceling of today's CSSWG meeting, I'm going to close this issue as per my last comment.

emilio commented 3 years ago

I still think we should have some discussion about this (even if it's on next week's meeting or something).

Note that what Gecko does and Blink does isn't just having different contrast thresholds (that is true for checkboxes, but not for a bunch of other form controls which do change to dark backgrounds in Blink but not in Gecko).

I'd still much rather have the author control this than inventing magic thresholds tbh. I'm happy to concede but I'd rather have at least a resolution on this.

josepharhar commented 3 years ago

Thanks for the response! I'm happy to discuss this in the weekly meeting.

Note that what Gecko does and Blink does isn't just having different contrast thresholds (that is true for checkboxes, but not for a bunch of other form controls which do change to dark backgrounds in Blink but not in Gecko).

I see, I added another test to https://accent-color.glitch.me and like you said, <input type=range> and <progress> don't respond to low contrast from accent-color in firefox. Is there anything you'd like to see happen here...?

chrome ![Screen Shot 2021-07-12 at 4 58 25 PM](https://user-images.githubusercontent.com/7681467/125370328-0b753500-e333-11eb-918b-78767c593119.png)
firefox ![Screen Shot 2021-07-12 at 4 58 10 PM](https://user-images.githubusercontent.com/7681467/125370353-1b8d1480-e333-11eb-9715-0c707accaecc.png)
css-meeting-bot commented 3 years ago

The CSS Working Group just discussed accent-color background colors and contrast, and agreed to the following:

The full IRC log of that discussion <fantasai> Topic: accent-color background colors and contrast
<fantasai> github: https://github.com/w3c/csswg-drafts/issues/6159#issuecomment-877023330
<fantasai> scribenick: fantasai
<fantasai> ??: tldr of issue is, the spec, as written today, takes one color for accent-color
<fantasai> ??: form controls drawn with that color need to make sure they have enough contrast with other parts
<astearns> s/??/masonf/
<fantasai> masonf: Opened issue to discuss
<fantasai> masonf: Depending on how implemented, if you change accent-color slightly, the contrasting pieces can change abruptly from light to dark color to maintain contrast
<fantasai> masonf: Where we are now is that we would prefer to just close the issue
<fantasai> masonf: The discussion has been, should we allow the developer to spec more than one color
<fantasai> masonf: and we went around about that last year, and don't want to open can of worms again
<fantasai> masonf: we think it'd be better for dev to be able to do that, but happy to just close issue and leave behavior up to UA
<florian> q+
<fantasai> emilio: Idk where the disagreement is...
<fantasai> emilio: What Chrome implements is that the switch to dark foreground color based on ??
<fantasai> emilio: Firefox does something similar, but not sensitive to color-scheme
<fantasai> emilio: It's different in some places
<fantasai> emilio: So I think specifying foreground/background pair would make sense here
<fantasai> emilio: but ...
<fantasai> masonf: The way we're currently implementing this, we have a set colors for light mode and dark mode
<fantasai> masonf: we calculate contrast ratio, and choose the one with most contrast
<fantasai> masonf: It seems to work ok
<fantasai> masonf: does guarantee minimum level of contrast
<fantasai> masonf: I think allowing specifying foreground+background color would be better
<fantasai> masonf: but the consensus previously was to allow UA to innovate on form controls
<fantasai> masonf: and allowing author to spec 2 colors would hamper that
<fantasai> emilio: why doesn't specify one color create a problem. 2 colors is more flexible
<astearns> ack florian
<fantasai> florian: Agree I don't want to reopen the entire conversation
<fantasai> florian: would like to stick to 1 color
<fantasai> florian: Agree that UA should pick however it want
<fantasai> florian: We might want to add a note reminding UAs that they don't have to pick *the most* contrasting color
<fantasai> florian: They could take into account e.g. color-scheme
<fantasai> florian: as long as enough contrast, have a choice of colors
<lea> Totally agree that accent-color should be 1 color
<fantasai> florian: but reopening question of one vs two, would prefer to avoid
<lea> q?
<fantasai> emilio: 1 color is going to be a mess compat wise
<fantasai> hober: To summarize, disagreement from what I remember, was not about having 1 or 2 colors in general
<fantasai> hober: was about how exact to specify how those two colors would be used
<fantasai> hober: which one should be foreground, which background, which pieces of which form elements should get which colors
<fantasai> hober: other side wanted to leave to UA, might be different plaform conventions or form styling that would lend themselves to using colors differently
<fantasai> emilio: I think it's silly to get stuck with one color
<fantasai> emilio: But then seems disagreement wasn't about one vs two colors
<fantasai> florian: multiple hours of disagrement
<fantasai> fantasai: There *are* two colors available to the UA. If 'color' is appropriate, you *can* use it.
<fantasai> emilio: I don't think that would work.
<RRSAgent> I'm logging. Sorry, nothing found for 'link'
<fantasai> fantasai: We can't do this in general, because form controls have different conventions and some of them are a lot more complicated than checkboxes
<lea> q+ to say, is this trying to solve a non-problem? I understand the abruptness may be jarring if you are trying multiple colors like in these testcases, but as long as the UA selected colors have sufficient contrast, is it really a problem? Are people going to animate accent-color?
<fantasai> florian: This discussion has happened already.
<fantasai> astearns: Any objection to moving forward with one color
<fantasai> emilio: no. I just think it's a bad decision
<lea> q-
<fantasai> RESOLVED: Close issue, one color accent-color for now
josepharhar commented 3 years ago

Closing as per meeting resolution