-
Notifications
You must be signed in to change notification settings - Fork 689
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
contrast-color()
MVP should support explicit light/dark colors rather than unspecified "very light/dark colors"
#11534
Comments
This also makes it clearer what the role of the different colors are, I think, which should remove the need for a keyword to identify the "base" color. |
The CSS Working Group just discussed
The full IRC log of that discussion<kbabbitt> lea: a while back we resolved to adopt an MVP for contrast-color<hober> q+ <kbabbitt> ...that returned very light and very dark color, up to UA what they would be <kbabbitt> ... and max version that returned white and black <kbabbitt> .. after working with designers more, I've seen they don't want arbtirary dark or light color <kbabbitt> ... they want specific tokens <kbabbitt> ... use this dark text color, not some arbitrary decided by browser coor <kbabbitt> ... in theory they could use max, get white and black, and transform it <kbabbitt> ... but it seems like an easy win if you could specify your light and dark versions <kbabbitt> ... ideally start with just providing dark one <kbabbitt> ... usually white is OK as text color but black isn't <kbabbitt> ... if you provide colors you can end up in situations with insufficient contrast <kbabbitt> ... but you can do that already <kbabbitt> ... so that doesn't make things worse <kbabbitt> ... it's in Safari but not implemented widely <kbabbitt> ... I would suggest a syntax that takes args for light and dark color, drop max, and if you don't provide args you get max behavior <kbabbitt> ... 1 arg is dark color with white as light color <kbabbitt> ... 2 args use those <kbabbitt> ... maybe UA can figure out which is which <kbabbitt> ... or we can be ordered <kbabbitt> ... pretty small syntax extension <kbabbitt> hober: really interesting problem, we had ? to talk through it internally <kbabbitt> ... it's intersting because it turns out contrast-color is something lots of people want <kbabbitt> ... for different reasons with different constraints <kbabbitt> ... after we whiteboarded it, we felt best way would be separate CSS functions for different use cases <kbabbitt> ... filed a new issue to suggest that <kbabbitt> ... space of desired behaviors & why we think they should be separate functions <kbabbitt> ... 2 proposals we kicked around <kbabbitt> ... one is maintainer of small/medium website who realizes that previous designer didn't use sufficient contrast <astearns> https://github.com//issues/11619 <kbabbitt> ... trying to bring website into modern world but don't have time to redesign it <kbabbitt> ... make smallest change they can that gives sufficient contrast <kbabbitt> ... other is designer at a company with well thought out brainding identity <kbabbitt> ...who really needs colors from a specific set <kbabbitt> ... use cases all over the place <kbabbitt> ... given this color, compute a contrasting color <kbabbitt> ... but ambiguous because color could be used for foreground, background, borders, etc. <kbabbitt> ... that's teh case we want contrast-color for <kbabbitt> .. other case, given a starting color and set of colors <kbabbitt> ... get the color from the set that contrasts most <kbabbitt> ... guaranteed color you get out is one of the ones you put in <kbabbitt> ... this also has variations because you might have different thresholds for borders etc <kbabbitt> ... then there's a case where you have a pair of colors for fg and bg <lea> q? <lea> q+ <kbabbitt> ... ask engine, make minimum tweaks to these <kbabbitt> ... one other that james craig though tof, put text on bg image <kbabbitt> ... who knows colors of bg image, but you want a color that contrasts sufficiently <TabAtkins> lea's proposal is more limited than "here's a list, pick the best" - instead you first determine whether white or black would be better, then let authors supply a replacement for white/balck <kbabbitt> ... all of these are interesting and probably need different functions <kbabbitt> ... disinclined to make color-contrast more complicated to do all these things <TabAtkins> q+ <kbabbitt> ... but do want to do all of these things <kbabbitt> ... using separate functions <astearns> ack lea <hober> https://github.com//issues/11619 <astearns> ack hober <kbabbitt> lea: when we resolved to do contrast-color it was because there was all this complex design space & use cases <kbabbitt> ... no good algorithm we could use right now <kbabbitt> ... [gives examples] <kbabbitt> ... so we resolved to leave it up to UA <kbabbitt> ... address most common case which is light + dark color <argyle> 17 use cases outline in my proposal from a couple years ago https://observablehq.com/@argyleink/contrast-color, sharing here to be added to the considerations <kbabbitt> ... these use cases exist but a lot of this is going back to debates where we got gridlock because it was such a big problem we couldn't move forwards <kbabbitt> ....we resolved to have this version because it addresses 80% of use cases without complexity <kbabbitt> ... looking to keep that <kbabbitt> ... maybe we'll solve others with same fn, maybe with different fns <kbabbitt> ... it's a matter of syntax <kbabbitt> ... poit of this proposal is to solve common case <florian> q+ <kbabbitt> ... don't think others are something we need to solve right now <kbabbitt> ... proposing a simple tweak over what we have right now <kbabbitt> ... supplying optional replacements for white & black <argyle> q+ <kbabbitt> ... it's not responsible for maintaining contrast ratios for you <kbabbitt> ... if previous proposal could be implemented easily this could be too <kbabbitt> ... hober's points are valid but lots of design work involved <astearns> ack TabAtkins <kbabbitt> TabAtkins: agree with lea <kbabbitt> ... trying to avoid reopening big design discussions <kbabbitt> ... this is a minimal edit to what WG decided on <kbabbitt> ... to address lea's concerns without opening new problesm <kbabbitt> ... I think we should accept this change, bikeshed syntax later <astearns> ack florian <kbabbitt> florian: worried this is a footgun <kbabbitt> ... yes if the color you get is actual black or white <kbabbitt> ... even if contrast function isn't perfect it will be good enough <lea> q? <kbabbitt> ...but here you allow user to supply something else <lea> q+ <kbabbitt> ... sometimes they'll be surprised what's picked because contrast won't be good <kbabbitt> ... sometimes what we have makes bad decisions but you know it's black or white <hober> qq+ to riff on florian's footgun <kbabbitt> ... if you're almost entirely black maybe not but depending on how far off you are, sometimes it will give you the wrong one between the two <astearns> ack hober <Zakim> hober, you wanted to react to florian to riff on florian's footgun <kbabbitt> hober: thats exactly my worry <kbabbitt> ... if we had a separate fn that solved, given set of colors give me one that contrasts <kbabbitt> ... that would be a simple change of syntax that would address that <TabAtkins> q+ to respond to tess <kbabbitt> ... while it's still a footgun, if you always have one color and it returns that regardless of contrast <kbabbitt> ... that's less of one because you're providing a set of colors <kbabbitt> ... this is areduced version of that where you're only providing 1 or 2 <kbabbitt> ... this is a guess because all we have to go on is intuition <florian> q? <kbabbitt> ... but I think authors are less likely to screw up in that case <kbabbitt> ... this isn't as good as a separte function but think we should try to solve the problem <astearns> ack argyle <kbabbitt> argyle: lea mentioned... I don't know any designers okay with partial color choice that didn't come from their palette <kbabbitt> ... most people I've talked to is the opposite <kbabbitt> ... they open palette and lcick around the pool <kbabbitt> ... if you have a set and want to pick from it, good feature, but not all designers explicitly want it <kbabbitt> ... we leave tasks up to browser a lot, sometimes it's not the right answer <kbabbitt> .... contrast prefs of user should be taken into account <kbabbitt> ... in high contrast mode this fn should return something relevant <kbabbitt> ... I've tried all algos, we should punt on forcing one <kbabbitt> ... we shouldn't be waiting for better algo <kbabbitt> ... enhancing what we have is good, white black or from a list <florian> q+ <kbabbitt> .... bad contrast is one of biggest a11y problems on web <astearns> ack lea <kbabbitt> lea: agree with argyle on taking HC into account <kbabbitt> ... re: footgun - I think people are comparing to ideal fn which we don't know how tyo build <weinig> q+ <kbabbitt> ... but without this, designers are specifying these manually <astearns> zakim, close queue <Zakim> ok, astearns, the speaker queue is closed <kbabbitt> ... we can be absolved of responsibility, they picked it <kbabbitt> ... re: having UA pick, there's not enough info in a tint to give you other tints of that color <kbabbitt> ... varying lightness is not sufficient in any color space <kbabbitt> ... even oklch <kbabbitt> ... still have to vary chroma to get tints <kbabbitt> ... if starting from a light color you can't derive darker variants <kbabbitt> ...without having accent color <kbabbitt> ...missing information <nicole> q+ <kbabbitt> ...I don't think UA can come up with a good color <kbabbitt> ...not a terrible result to get black & white if nothing provided <kbabbitt> ... I think for the people picking madly around a color picker, they can deal with black & white <kbabbitt> ... I don't think UA generating dark color would help them very much <astearns> ack TabAtkins <Zakim> TabAtkins, you wanted to respond to tess <fantasai> scribe+ <fantasai> TabAtkins: Responding to Tess, the big thing that blocked us last time was the idea of having a function that could pick from a list of colors *because* we know our current contrast algo sucks <kbabbitt> TabAtkins: our existing algo sucked and we didn't have a good replacement <kbabbitt> ... that's why we subsetted down to 2 color case <kbabbitt> ... white and black can go a little wrong but hard to go very wrong <kbabbitt> ... going back on that will reopen every problem we had before deadlock was resolved <kbabbitt> ...it is possible to footgun by supplying dark color instead of black <kbabbitt> ... don't do that, we'll tell them not to do it in spec <argyle> just sharing this again, as this lets you see returned colors from any contrast algo, from a list, or max white/black OR it can discover a color. all of these options we're sharing here are in this demo, and you can see how totally decent the results are https://observablehq.com/@argyleink/contrast-color <kbabbitt> ... can supply own colors, they should be very dark very light <kbabbitt> ... still gets us to a defensible spot even if we're stuck with ? as contrast algo <kbabbitt> s/?/WCAG2/ <astearns> ack florian <kbabbitt> florian: building on TabAtkins and lea were saying <kbabbitt> ...thinkinh of it as a footgun compared to doing it manually <kbabbitt> ... problem case is a light on dark theme where dark isn't very dark <kbabbitt> ... and you ask for contrast between middle color and give me black or white <kbabbitt> ... and get kind of gray <kbabbitt> ... to contrast on kind of gray <kbabbitt> ... and this fn which is supposed to give you good contrast, doesn't <kbabbitt> ... on one hand, don't do this, on the other hand this is the fn that ghives me contrasty <kbabbitt> ... so the only thing I can put in there is gray <kbabbitt> lea: isn't that a problem with current version? <kbabbitt> florian: no because it returns black <kbabbitt> ... it won't return middle gray <kbabbitt> ... if you can't use black, you won't use function <kbabbitt> ... you won't supply it middle gray, you won't use it at all <astearns> ack weinig <fantasai> +1 <kbabbitt> weinig: second time I've impled this function, shipped it behind a flag <TabAtkins> as lea pointed out earlier, you can *turn* white/black into chosen colors via RCS, fwiw <fantasai> that's more explicit though. The author won't think they're getting an actual contrast computation <kbabbitt> ... how do we get to the point where this is good enough and get user feedbacl? <kbabbitt> ... can we resolve on this version and try it out, see feedback <lea> If we can't reach consensus on this, I wonder if we can just drop `max` (and do white/black by default) so that we can extend the function later with something like this <fantasai> +1 lea <kbabbitt> ... seems unnecessary to keep iterating if it's contentious <kbabbitt> astearns: not hearing consensus for any particular resolution <kbabbitt> ... let's take back to issue <kbabbitt> ... we may decide to extend as lea suggests <kbabbitt> ... might need different version <miriam> +1 <lea> (fwiw I think that's a better design *anyway*) <TabAtkins> i'm fine with that <kbabbitt> Proposed: drop `max`, do white/black by default and allow extension points later <kizu> +1 <fantasai> +1 <lea> 🎉 <kbabbitt> RESOLVED: drop `max`, do white/black by default and allow extension points later <argyle> +1 that's how my proposal works in that observable |
In #9166 we resolved to add
contrast-color(<color>)
that would generate either "a very light" or "a very dark" color, depending on what contrasts better with its argument, andcontrast-color(<color> max)
which would producewhite
andblack
.However, in my experience working with designers, this "very light or very dark color" stuff would not fly. Like, at all.
white
is often acceptable as the text color for a darker background, but for lighter backgrounds,black
(or an unspecified "very dark color") usually less so. Usually designers want a specific dark token for the light background case, not just an unspecified "very dark color".Additionally, if you look at the color tokens specified by designers, it is actually very, very hard to generate a good dark color if all you know is the lightest tint. E.g. take a look at this Tailwind blue scale from https://palettes.colorjs.io/palettes/tailwind/ :
If all you're given is blue 50, how can you calculate anything that even moderately resembles blue 950?? It's not just lightness. Note how the chroma is much higher, note how the hue shifts a little. This is true for most of them, this not a carefully picked example.
Yes, this means that authors could specify colors that do not have sufficient contrast. But with the current design, they still can: either by not using
contrast-color()
at all because it doesn't serve their needs, or by transforming the result with RCS in convoluted ways. I think "garbage in, garbage out" is okay. If people don't think so, perhaps we could introduce a safeguard and allow (with a MAY) the function to still returnwhite
/black
if the colors passed have particularly egregious contrast (what that is could be UA-defined).Syntax
Since at this point we're sufficiently early in the game that we can change
contrast-color()
in backwards incompatible ways, I would propose this redesign:max
, makewhite
andblack
the base caseBasically, the grammar would become:
Or, alternatively, if we want a more expressive version that allows us to extend more easily, it could be something like this:
This would allow us to down the line support specifying the foreground color and determining the background color, though I'm not sure how a version that defaults to white but allows you to specify the dark color could look like (the grammar above allows you to specify both or none).
Perhaps something like this combines the best of both worlds:
The text was updated successfully, but these errors were encountered: