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] color-contrast() should support ranges of candidate colors, not just discrete color candidates #7360

Open
LeaVerou opened this issue Jun 14, 2022 · 5 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

When designers are picking colors to pass a certain contrast ratio, they usually adjust a given coordinate, in a given color space (usually lightness). The current color-contrast() syntax only allows providing specific candidate colors, so I worry we will see a lot of this:

background: var(--color);
color: color-contrast(var(--color) vs 
	lch(from var(--color) 100% c h),
	lch(from var(--color)  90% c h),
	lch(from var(--color)  80% c h),
	lch(from var(--color)  70% c h),
	lch(from var(--color)  60% c h),
	lch(from var(--color)  50% c h),
	lch(from var(--color)  40% c h),
	lch(from var(--color)  30% c h),
	lch(from var(--color)  20% c h),
	lch(from var(--color)  10% c h),
	lch(from var(--color)   0% c h)
);

It would be good if there was a syntax to provide the candidate colors as a range, either by reusing <gradient>, or with a watered down microsyntax:

  • such as a functional syntax range(<interpolation-method>, <color>#)
    • example: range(in lch, lch(from var(--color) 100% c h), lch(from var(--color) 0% c h)))
  • or a keyword-based syntax like <color> to <color> <interpolation-method>?
    • example: lch(from var(--color) 100% c h) to lch(from var(--color) 0% c h) in lch

The range would be considered ordered, and browsers would return the first color in the range that passes the target contrast (which they may decide to calculate via binary search). It may make things simpler if ranges can only be from one color to another color.

(Issue filed following breakout discussions between @svgeesus, @fantasai, @argyleink and myself)

@BillGoldstein
Copy link

Considering there's been some WCAG3 discussion of maximum contrasts, too, e.g for large text...so as not to burn one's retinas :)

Maybe more than a single range syntax might be appropriate. Think some along the lines of min(), max(), minmax(), maxmin(), and clamp(). In the clamp(min, preferred, max) maybe even mid() for preferred.

Also perhaps consider a "by" increment, and or a "using" named-curve.

Feel free to separate any/all of these into their own issues.

@BillGoldstein
Copy link

Though not in color-6, some sort of element-level font-size query is also needed.

@Myndex
Copy link
Member

Myndex commented Jun 19, 2022

Hi Bill @BillGoldstein

...some WCAG3 discussion of maximum contrasts...

Yes, currently testing a maximum APCA contrast of what is currently calculated as Lc 90, this is on the live SAPC development tool along with a spread of use-case lookups.

There are a variety of factors that make a normative guideline for maximum contrast tricky:

  • It is extremely polarity sensitive.
  • KEY: It is LESS about a maximum contrast and MORE about a maximum luminance relative to adaptation state.
    • Since only estimated relative luminance can be determined, and there are privacy considerations for attempting to access the other needed parameters, this might be a showstopper, at least as a normative standard (i.e. only listed as an informative condition).
    • Since adaptation state is important, and the 3-way and 4-way APCA versions are considered future iterations (one step at a time, LOL) only local adaptation is directly considered, and that's not enough for predicting "max" contrast.
    • Newer HDR displays have modes viewing sRGB material that is eye-scorching, and then other modes marked "readable", and again, content authors have no control here. (See SAPC-APCA discussion #74 for discussion of this exact use case).
  • font weight and size are also key relevant factors, and for that matter so is age and related issues pertaining to ocular media, disability glare, etc.

So, at the moment, Lc 90 is an advisory maximum, especially in dark mode. But a better advisory MIGHT be, limit the color to no brighter than the equivalent of about #e6e6e6

A related advisory is for light mode, to keep the background under text to less than about #e6e6e6 as well.

Your mileage may vary, these values are under investigation.

Here's a visual example of some of the factors:

New Eye Strain 2022

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Ranges of Candidate Colors, and agreed to the following:

  • RESOLVED: punt for now, revisit later
The full IRC log of that discussion <fantasai> Topic: Ranges of Candidate Colors
<lea> github: https://github.com//issues/7360
<emilio> lea: there's a discontinuity between how designers design UI and how the contrast-color() function works
<emilio> ... they often have a base color and adjust coordinates (usually lightness) to get sufficient contrast
<emilio> ... right now it's possible but you'd need to provide a bunch of colors to simulate a range
<emilio> ... it'd be nice if you could simplify that usage
<emilio> ... not sure if it would need special syntax, or even if we want to do this
<astearns> ack dbaron
<emilio> ... we might want to punt on it and do it only if people actually do this
<emilio> dbaron: when you suggested syntax, before you said gradient my initial reaction was to use the interpolation syntax
<lea> q?
<emilio> ... I think you could reuse the interpolation syntax without specifying the end
<emilio> ... it's basically gradient without direction / radial stuff
<emilio> ... other thought is that this is difficult to explain with multiple contrast functions
<lea> q+
<emilio> ... if you specify something that's a range of color we specify the order in which you process them in
<emilio> q+
<astearns> ack lea
<TabAtkins> q+
<emilio> lea: I think before we dive down into details we should decide if we want to pursue this
<emilio> ... what that syntax would look like is secondary
<astearns> ack emilio
<fantasai> emilio: I think I'd rather act on it for now
<fantasai> emilio: there are a bunch of things to figure out, e.g. what are the steps you use for lightness?
<fantasai> emilio: what's the resolution of all the colors you try?
<fantasai> emilio: you may try 1000s of colors to find somehting
<fantasai> emilio: seems a bit unpredictable, perf-wise
<lea> q+
<fantasai> emilio: I guess you can binary search, maybe?
<astearns> evaluating all the colors for multiple algorithms seems expensive
<fantasai> emilio: assuming contrast is alwasy increasing or decreasing
<lea> q-
<fantasai> emilio: so unless we find ppl actually doing this,
<dbaron> yeah, I think you can't assume that contrast is always increasing/decreasing
<fantasai> emilio: if you pass 1000 colors, then worst case you evaluate 1000 colors
<fantasai> emilio: For now I'd rather defer this
<fantasai> emilio: I'd rather get the bits we know we want right, and then if we want to extend, we can always do it
<astearns> ack TabAtkins
<emilio> TabAtkins: you can't assume contrast is monotonic if you interpolate hue
<emilio> ... so sampling frequency becomes important
<lea> I actually agree
<fantasai> s/rather act/rather punt/
<emilio> ... so I say we punt for now
<lea> RESOLVED: punt for now, revisit later
<lea> github: https://github.com//issues/5153
<emilio> github: https://github.com//issues/7360

@danburzo
Copy link

danburzo commented Mar 7, 2023

Color ranges, specifically using interpolation syntax with which authors will be familiar from gradients, sound like a neat way to derive a given color to achieve sufficient contrast from the base color (also captured in #5153).

Given there can't be any assumptions about the monotonicity of contrast, so binary search is unhelpful, would it make sense to allow authors to define the number of samples the range computes to, with a default that makes it reasonable to evaluate the list from start to end against one or more contrast targets? And possibly an upper limit so author's can't inadvertently degrade performance on less powerful devices?

Something along the lines of:

range(<number>? <interpolation-method>, <color>#)

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

7 participants