Re: [csswg-drafts] [css-color-4] Color modifications proposal: extending color functions (#3187)

I figured I'd make some edits to the original proposal that reflect the discussion so far, and my take on the issues raised.

--------

### Proposal

This is loosely inspired from the current practice of defining major theme colors as color components in a variable (e.g. `--color: 180, 60%`) and then using them in color functions (e.g. `hsl(var(--color), 90%)`). However, this is simple textual substitution, which is insufficient, and imposes constraints on how the base color is defined.

I’m proposing to extend all color functions to allow for a `<color>` argument, preceded by the keyword `from` to make it clear that this is a color (in case a variable is used). If the color argument is present, it is first converted to the target color space of the function, then the remaining arguments set or modify its coordinates in that color space. A `_` keyword represents the value of each coordinate and can be used by itself to mean "no change", or in `calc()` for relative modifications. For example, if a function’s grammar is `<number>{3}`, it will become `from <color>? (<number> | _){3}`.

Before any modification, the color would be converted to the target color space of the function used. This means that modifications using `hsl()` can be lossy (since the color would need to be converted to sRGB), but there is no such problem with `lab()` or `lch()`. However, any syntax that allows modifying HSL or RGB coordinates would have the same issue, at least this syntax makes the conversion more explicit.

Directly setting arguments is not sufficient for most modifications, since it cannot perform relative modifications (e.g. "increase L by 10%" instead of "set L to .3"), which are far more common use cases. We can re-use `calc()` to allow for relative modifications. 

With the syntax for relative modifications, this addresses most desired adjustments, and expands naturally with every new color function. Tint and shade could be relative modifications on `hwb()`, though adjusting the L of Lab/LCH is better as it's lossless (and produces fantastic results).

### Examples

- `lch(from var(--accent1) calc(_ * 1.2) _ _)` would adjust `var(--accent`) to be a little lighter.
- `lch(from var(--accent1) _ 230 _)` would adjust `var(--accent`) to be very bright (sets its Chroma to 230).
- `rgb(from indianred, 255 _ _)` would produce the same color as `indianred` but with 255 in the red channel. The result would be in sRGB since that's what the `rgb()` function produces.

### Benefits of this syntax

- Color spaces are an intrinsic part and not an afterthought.
- Extends on syntax that authors are already familiar with (existing color functions and `calc()`). No need to learn different ways to refer to the same color components.
- Can be understood by anyone who understands the existing color functions, even if they are unaware that a modification syntax exists.
- Makes the target color space very obvious, since it looks like creating a new color.
- Every new color function comes with new color adjusters for free, no need to learn anything new besides using the color function.
- Supports both relative and absolute adjustment, and relative could be either additive (e.g. "add 10% to lightness") or multiplicative (e.g. "multiply lightness by 120%"), or even a combination of both, since it can utilize the entire power of `calc()`.

### Drawbacks

- Gives authors too much rope to hang themselves with: Most will resort to `hsl()` modifications because that's what they're familiar with, even though `lch()` produces better results and takes maximum advantage of the device gamut. It’s easy to clip the modified color to sRGB, since authors are very familiar with HSL and many would use that. However, any color adjustment syntax that supports adjusting hue, saturation, lightness would have the same issue. At least this syntax makes it obvious that you are creating an `hsl()` color, with the gamut limitations that this comes with.
- Might be too complex. Do we really need adjustment of every possible color channel in every color space, or would it be sufficient to just use L, C, H and cover the main use cases?
- Does not address contrasting colors or blending of two or more colors, these could need to be done via separate functions.
- Stupid lossy transformations can be defined, like `color(hsl(color(mycmyk .1 .2 .3 .4) mycmyk 60%) .4)`. However, a) any sufficiently powerful syntax will allow for silly things, and b) see point above.

-- 
GitHub Notification of comment by LeaVerou
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/3187#issuecomment-499126198 using your GitHub account

Received on Wednesday, 5 June 2019 15:12:37 UTC