- From: Lea Verou via GitHub <sysbot+gh@w3.org>
- Date: Wed, 06 Mar 2024 03:34:29 +0000
- To: public-css-archive@w3.org
LeaVerou has just created a new issue for https://github.com/w3c/csswg-drafts:
== [css-color-5] `color-scale()` for interpolating across multiple colors ==
During the discussion in #9992 it occurred to me that one of the things that could really help simplify the color-related design systems use cases would be a way to define a gradient line and pick a color on it.
## Why?
- As a primary use case, authors often need to define scales of colors with interim colors inserted to adjust the interpolation, and `color-mix()` is not very friendly to that. Super common example: the good-bad scale of red, orange, yellow, green.
- Design systems could then define color scales and pass them around in variables, which would make functions a much more appealing solution for actually selecting points on those scales.
- It makes interpolation with arbitrary manual interim points much easier, without requiring special overfit syntax in variable groups to cater to this.
- The scale specification should be compatible with gradient color stops so that authors can debug them by simply throwing them into a `linear-gradient()`.
## Syntax
### Option 1: Single function for both *defining* the scale, and _selecting_ a color
```
<color-scale()> = color-scale ( <percentage> / <color-interpolation-method>?, <abstract-color-stop-list> )
<abstract-color-stop-list> = <abstract-color-stop> , [ <abstract-color-hint>? , <abstract-color-stop> ]#
<abstract-color-stop> = <color> <percentage>?
```
Example usage:
```css
--tints-green: white, var(--color-green), black;
--color-green-900: color-scale(90% / var(--tint-green));
```
This is basically modeled after `linear-gradient()` with the non relevant parts removed (lengths, `to <whatever>`, angles).
It could also allow `<1d-image>` / `stripes()` to facilitate discrete scales.
The reason the percentage is separated from the rest with a `/` is to facilitate storing the actual scale part into variables and passing them around without having to worry about whether you need to specify a comma or not (depending on whether the scale has a `<color-interpolation-method>`).
Pros:
- By passing a list of arguments around, these can produce *both* a color scale *and* various types of gradients (without gradients having to be extended in any way)
- Color stop list could even be extended by adding more stops on either side
Cons:
- Scale variables don't make sense by themselves, as they're just a comma-separated list of colors.
### Option 2: Separate scale definition and color selection
This syntax decouples the scale from the color selection.
It seems more conceptually sound, but also too many parens.
```
<color-scale> = color-scale ( <color-interpolation-method>?, <abstract-color-stop-list> )
<abstract-color-stop-list> = <abstract-color-stop> , [ <abstract-color-hint>? , <abstract-color-stop> ]#
<abstract-color-stop> = <color> <percentage>?
<color-pick()> = color-pick(<percentage> of <color-scale>);
```
Example:
```css
--tints-green: color-scale(white, var(--color-green), black);
--color-green-900: color-pick(90% of var(--tints-green));
```
the parens could be reduced if it would be possible to define tokens like:
```
<color-scale-color> = <percentage> of <color-scale>
```
Example:
```css
--tints-green: color-scale(white, var(--color-green), black);
--color-green-900: 90% of var(--tints-green);
```
but I suspect @tabatkins will have a good reason to rule that out 😁
We could also make it a variant of `color-mix()`:
```
<color-mix> := color-mix(<percentage> of <color-scale>)
```
Example:
```css
--tints-green: color-scale(white, var(--color-green), black);
--color-green-900: color-mix(90% of var(--tints-green));
```
Though since conceptually we're not mixing anything, I don't think this is worth it.
## More Examples
### Transparent variations of a base color
Option 1:
```css
--color-neutral-a: var(--color-neutral), transparent;
--color-neutral-a-90: color-scale(90% / var(--color-neutral-a));
```
Option 2:
```css
--color-neutral-a: color-scale(var(--color-neutral), transparent);
--color-neutral-a-90: 90% of var(--color-neutral-a));
```
### Success/failure scales
This is super common to communicate varying levels of success/failure.
There are two main forms: red - orange - yellow - green - dark green, or red - white - green.
E.g. see screenshot from Coda’s conditional formatting:
<img width="329" alt="image" src="https://github.com/w3c/csswg-drafts/assets/175836/9215ca1c-89e2-4d9a-aa2e-04de367afc91">
Especially the red - orange - yellow - green scales almost always require manual correction, and cannot be done with a single 2 color interpolation (yes not even in polar spaces).
With `color-scale()` they can be as simple as:
```css
:root {
--color-scale-bad-good: in oklch, var(--red), var(--orange), var(--yellow) 50%, var(--green) 90%, var(--dark-green);
}
.badge {
background: color-scale(var(--percent-good) of var(--color-scale-bad-good));
.great { --percent-good: 100% }
.good { --percent-good: 80% }
.ok { --percent-good: 60% }
.fair { --percent-good: 40% }
.poor { --percent-good: 20% }
.terrible { --percent-good: 0% }
}
```
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/10034 using your GitHub account
--
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config
Received on Wednesday, 6 March 2024 03:34:31 UTC