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-5] color-contrast() needs resolution logic if 2 or more have the same contrast #4732

Closed
argyleink opened this issue Feb 3, 2020 · 14 comments

Comments

@argyleink
Copy link
Contributor

Spec draft
https://drafts.csswg.org/css-color-5/#colorcontrast

Example

foo {
  --bg: hsl(200 50% 80%);
  --purple-in-hsl: hsl(300 100% 25%);
  color: color-contrast(var(--bg) hsl(200 83% 23%), purple, var(--purple-in-hsl));
}

verify contrast scores: [hsl(200 83% 23%), purple, var(--purple-in-hsl)]

Given purple, hsl(200 83% 23%), & hsl(300 100% 25%) all have the same contrast with --bg, which wins? First match, cascade, your idea?

@svgeesus
Copy link
Contributor

svgeesus commented Feb 3, 2020

Good catch, @argyleink I agree this needs to be specified

Given that the second parameter to color-contrast is a list of alternatives, then similar to other lists in CSS I suggest that the earliest match wins. In other words the logic is:

  • if the list has one item, it wins
  • if the list has two or more items, the first is the temporary winner but the next takes the winning place if it is better, and so on down the list

We also need to specify what happens if the first param is not a valid color, or any item of the second param are not valid colors.

  • thus, a later item with the same score as an earlier item will not win.

@svgeesus svgeesus added the css-color-5 Color modification label Feb 3, 2020
@svgeesus
Copy link
Contributor

svgeesus commented Feb 3, 2020

@una @LeaVerou should I go ahead and spec "first in list wins" or do you have other ideas on a resolution?

@svgeesus svgeesus self-assigned this Feb 3, 2020
@tabatkins
Copy link
Member

Yeah, since there's no further context to decide ties, going with first-wins seems reasonable.

@svgeesus
Copy link
Contributor

svgeesus commented Feb 4, 2020

Not so fast on the closing, Chris :)

We also need to specify what happens if the first param is not a valid color, or any item of the second param are not valid colors.

@svgeesus svgeesus reopened this Feb 4, 2020
@svgeesus
Copy link
Contributor

svgeesus commented Feb 4, 2020

verify contrast scores: [hsl(200 83% 23%), purple, var(--purple-in-hsl)]

Note that these all give the same contrast of 6.08, when rounded to 3 significant figures as your tool does, @LeaVerou but when a higher precision is used, purple wins. I made that point in the spec text.

@argyleink
Copy link
Contributor Author

first wins, i dig it.
and nice catch on the higher precision contrast score! makes me wonder where the implementers will get their scoring algorithm from and whether or not we need to provide it (or one that works with CIE and offers higher precision) in the spec?

@svgeesus
Copy link
Contributor

svgeesus commented Feb 5, 2020

makes me wonder where the implementers will get their scoring algorithm from

The algorithm is given in WCAG 2.1 and the inputs are the relative luminances of the two colors being compared.

In utilities.js I have added that function, for convenience, although the inputs are sRGB only (same as WCAG):

function contrast(RGB1, RGB2) {
    // return WCAG 2.1 contrast ratio
    // https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio
    // for two sRGB values
    // given as arrays of 0.0 to 1.0

    var L1 = sRGB_to_luminance(RGB1);
    var L2 = sRGB_to_luminance(RGB2);

    if (L1 > L2) return (L1 + 0.05) / (L2 + 0.05);
    return (L2 + 0.05) / (L1 + 0.05);
}

I also have a function sRGB_to_luminance(RGB) in utilities.js, primarily to help writing examples.

Notice that relative luminance is just the Y in CIE XYZ and conversions.js provides sample code to convert any of the predefined colorspaces to XYZ (for the rgb spaces, in two steps: undo gamma correction, then convert linear rgb to XYZ). The same goes for Lab to XYZ (two steps, convert to D50 XYZ then adapt to D65 XYZ) and LCH to XYZ (three steps, first convert LCH to Lab).

And even for calibrated spaces like CMYK etc, if a color profile is provided.

It is always just a case of computing two luminances, Y1 and Y2, then doing the simple ratio (with 5% flare compensation).

Luminance has been defined by an international standard since 1931, we don't need to define it in CSS just document how it is calculated, to help developers.

@svgeesus
Copy link
Contributor

svgeesus commented Feb 5, 2020

I should probably add another contrast example where the color list includes display-p3, prophoto-rgb, and lab and lch values.

@argyleink
Copy link
Contributor Author

feels like there's clear resolution on this issue, it's ready to close yeah?

@svgeesus
Copy link
Contributor

We also need to specify what happens if the first param is not a valid color, or any item of the second param are not valid colors.

@tabatkins
Copy link
Member

Both of those cases are "doesn't match the grammar" and thus are invalid, right?

@svgeesus
Copy link
Contributor

Yes, I assumed so. Or, if a custom property is involved and the parser can't tell, invalid at computed value time.

Do we need t say either of those things explicitly or is it just assumed?

@tabatkins
Copy link
Member

They're just assumed. If you write something into a property that takes <color> that doesn't match the grammar of anything defined under the <color> nonterminal, it's invalid and the appropriate error-handling happens automatically.

@svgeesus
Copy link
Contributor

svgeesus commented Mar 3, 2020

OK in that case this can indeed be closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants