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

[css-color-6] color-contrast() with automatic continuous lightness adjustment #5153

Open
LeaVerou opened this issue Jun 2, 2020 · 4 comments
Labels
a11y-tracker Group bringing to attention of a11y, or tracked by the a11y Group but not needing response. Closed Deferred css-color-6

Comments

@LeaVerou
Copy link
Member

LeaVerou commented Jun 2, 2020

Current definition: https://drafts.csswg.org/css-color-5/#colorcontrast

While providing a list of colors and picking the one that satisfies a certain contrast constraint is useful for some use cases, it is quite a hassle for others. In virtually every case I've used a contrast calculator, I had a fairly good idea of what colors I wanted, and I just adjusted the lightness of one of the two until it passed WCAG. To use the color-contrast() in its current form would basically mean precomputing a list of various lightnesses, which is suboptimal.

I would find it far more useful for my use cases, if in addition to a list of colors, I could provide just a background and foreground color, optionally a min contrast ratio (would default to 4.5), and optionally a direction to adjust the foreground color (would default to closest).

I.e. something like this:

color-contrast() = color-contrast([lighten | darken]? <color> on <color> [to <number>:1]? )

E.g.

color-contrast(lighten rebeccapurple on wheat to 3:1);

If lighten or darken are provided and white/black respectively don't pass the minimum contrast, we could either go the other direction, or just return white/black.

Of course lightness would be LCH lightness, not HSL lightness. And before you point out that contrast is relative luminance (Y) based and not lightness based: Yes, I'm aware, but:

  • Two colors with the same Y also have the same L
  • Y and L are comonotone (they increase/decrease together, albeit at different rates). I.e. For any colors C1, C2, if Y1 > Y2 then L1 > L2 and vice versa.

So, if there is a lighter/darker color that will pass a given contrast ratio, increasing/decreasing LCH lightness will find it.

@LeaVerou LeaVerou added the css-color-5 Color modification label Jun 2, 2020
@svgeesus
Copy link
Contributor

svgeesus commented Jun 3, 2020

This seems to respond directly to what @mirisuzanne wanted

adjust given color to meet a particular ratio

However, most of the discussion in that thread was about picking the color from a list which meets a given ratio, so it is good to discuss this, very different functionality, here. One is for the case where a palette of colors is already chosen, and this one is where a starting color can be freely modified to meet some set of criteria.

@jhogue also wrote about that

I created a Sass function called a11y-color() that takes a color to change, a color to keep the same, a WCAG Level (AA or AAA), a font size, and whether or not a font is bold to calculate and change the first color (color to change) to a color that passes the supplied WCAG Level.

@Myndex
Copy link
Member

Myndex commented Mar 1, 2021

Hi @LeaVerou and @svgeesus

This is an old issue, but I see it's still open, so:

In WCAG 2.x, as a color pair gets darker, the reported contrast becomes increasingly inaccurate, so I am concerned that "automated" contrast methods using WCAG 2.x math could have negative consequences, if there is no designer watching to manually boost the contrast.

I have a couple Gists with examples you might like to see on this:

Orange You Wondering About Contrast?

The Lighter Side of Dark Backgrounds

Constant Contrast in APCA

On the subject of constant contrast within a range of lightnesses, at the SAPC site there is "Research Mode", and in that mode, select the "Constant Contrast" radio button. At the far left of the control slider is a numeric entry for the target contrast, and the slider allows you to adjust the lightness/darkness. The light-green range on the slider is the "constant contrast range", and the other ranges indicate when either the hi or lo color is at max #ff or #00, or the dark color is below 4.0Y or so. The slider control is in the middle between the hi and low color.

Here's the SAPC research version link: https://www.myndex.com/SAPC/

Lemme know if questions...

Thank you

Andy

@NateBaldwinDesign
Copy link

I would love to see this implemented!

This problem was the foundational basis for creating Leonardo, which gives designers & developers the ability to generate a color based on the target contrast ratio.

Putting this type of functionality directly into the CSS Color Module spec seems like the right approach. I especially like the syntax as it's very simple and easy to understand:

color-contrast(lighten rebeccapurple on wheat to 3:1);

I have some thoughts regards to how the color is lightened or darkened that I would like to express.

If simply modifying LCh lightness value of a color, at some point the results will be out of sRGB gamut. One mechanism to correct this would be to clamp to sRGB, however the resulting colors are not likely to be closely aligned with designers' intent.
image
This is problematic in that for certain colors, the perceptual shift in chroma could be dramatic. A slightly lighter value of a color vs a much lighter value of the same color can appear not harmonious.

Another possible approach would be to interpolate from the original color directly to white and black. However this approach has a more pronounced problem as the previous method for some colors (but not all, as in the example below).
image

The method I would like to recommend is something in between. Retaining chroma as close as possible to the original color is preferred, however it should have a smooth rate of change as the color approaches white and black. From what I've seen in this area, a smoothing curve such as Catmull-Rom does a great job of this.
image

Now to address the elephant: Yellow.
Yellow is by far one of the most difficult colors to work with in this space, because darker values of yellow (within sRGB) never look right. Even when interpolating in LCh, given the gamut restrictions of sRGB, the colors are undesirable.
image

The above gradient illustrates a linear interpolation from #ffee00 to white and black in LCh color space. The sample swatches I've highlighted help to illustrate that "darker yellow" is not a favorable color.

As a designer, we may wish to adjust the hue along with chroma in order to make sure colors appear more aesthetically pleasing as they get lighter or darker. In this case, we could solve it by adding more "key colors" to our argument:

color-contrast(darken #ffee00, #755000 on wheat to 3:1);

By adding the darker orangish color to the argument, you could interpolate from white, to #ffee00, to #755000, and to black. Now, the sampled colors take on more of an Amber quality, making sure the color is still rich (having and appearing to have higher chroma) as it gets darker.
image

Since CSS doesn't inherently provide a great way to visualize how a color will change relative to others, this approach could ensure that the original color's aesthetic qualities are respected within the confines of the sRGB gamut.

@svgeesus svgeesus added css-color-6 and removed css-color-5 Color modification labels Jul 27, 2022
@svgeesus svgeesus changed the title [css-color-5] color-contrast() with automatic continuous lightness adjustment [css-color-6] color-contrast() with automatic continuous lightness adjustment Jul 27, 2022
@LeaVerou LeaVerou moved this to Tuesday in 2022 New York Meeting Aug 1, 2022
@LeaVerou LeaVerou added Agenda+ F2F a11y-tracker Group bringing to attention of a11y, or tracked by the a11y Group but not needing response. labels Aug 1, 2022
@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed color-contrast() with automatic continuous lightness adjustment, and agreed to the following:

  • RESOLVED: Defer for now
The full IRC log of that discussion <emilio> Subtopic: color-contrast() with automatic continuous lightness adjustment
<emilio> github: https://github.com//issues/5153
<emilio> lea: so this is similar to the previous problem we discussed where you have a given color and you want to lighten or darken it enough so that you get decent contrast
<emilio> ... I think in this case the contrast does tend to be monotonic
<emilio> ... so you might be able to binary search
<emilio> ... we could punt as well for now
<emilio> TabAtkins: I don't think this one is problematic but might be worth punting for the moment
<emilio> q
<emilio> q+
<emilio> miriam: I think this is useful, it's something that a preprocessor can do in a bunch of cases, but it's ok if we delay it
<emilio> astearns: people want to ship contrast-color() so the simpler the better for now
<fantasai> emilio: was going to mention, what we use internally for a lot of these use case
<fantasai> emilio: it's not lightness, luminance more generally
<fantasai> emilio: in order to replicate a default color palette with an arbitrary accent color
<fantasai> emilio: we have a function to adjust the function to a given luminance
<fantasai> TabAtkins: that's just relative color syntax
<astearns> ack emilio
<fantasai> emilio: I think unless we have any pressing issue, I vote to punt
<fantasai> emilio: this seems extremely similar to what we discussed
<fantasai> emilio: so maybe punt
<emilio> RESOLVED: Defer for now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a11y-tracker Group bringing to attention of a11y, or tracked by the a11y Group but not needing response. Closed Deferred css-color-6
Projects
Status: Tuesday
Development

No branches or pull requests

6 participants