[csswg-drafts] [css-color-4][Editorial?] Clarify that `none` is preserved in calculations (#10211)

LeaVerou has just created a new issue for https://github.com/w3c/csswg-drafts:

== [css-color-4][Editorial?] Clarify that `none` is preserved in calculations ==
_(This came out of my comment here: https://github.com/w3c/csswg-drafts/issues/10151#issuecomment-2052685363 and subsequent comments)_

The spec is currently unclear about this, though @svgeesus made the case that this is editorial. @romainmenke thinks it's a substantive change. **Regardless, we need to fix it ASAP to avoid web compat roadblocks.**

Currently, css-color-4 is a little unclear on what happens with `none` values in authorland calculations, and implementations are currently converting `none` to `0` if used in `calc()` and other math functions, which comes up a lot in Relative Color Syntax. This was never our intent, the only reason converting `none` to `0` exists is that we don't want to be exposing color space conversion math, and/or sometimes you literally need to _output_ a color that includes `none` components.

Even when converting to different color spaces, the spec already includes the concept of [analogous components](https://drafts.csswg.org/css-color-4/#analogous-components), to minimize `none` → `0` conversions, and in #10210 I proposed expanding it a bit.

Note that while `none` was originally conceived to express achromatic colors and the chroma of white & black, it is actually useful _way_ beyond that, as it allows expressing _parameterizable colors_, in a way that decouples the calculation from the color (unlike RCS which requires them both at the same time). You only specify the bits that don't change (e.g. hue), leave the rest `none`, and let normal CSS operations take their course. E.g. interpolating any (polar) color with `oklch(calc(none - 0.4) none none)` interpolates with a darker version of that color. Sure, you can do all these things with pure RCS, but this decouples the parameter from the modification entirely, you don't even need to _know_ what you’re interpolating with, it just works.

Converting to `0` if used in calculations serves no purpose other than simplifying implementations, reduces `none`’s usefulness in creating dynamic colors that can be passed around, and introduces several problems:
- Discontinuity since e.g. `h` and `calc(h)` are not the same, 
- It makes browser interpolation magic compared to what authors can do with `calc()` or even `calc-mix()`. 
- Disregards author intent

I propose we introduce the concept of _`none`-containing component_ and clarify that:
- Calculations preserve `none`. Meaning, `calc(h + 20)` in RCS would become `calc(none + 20)`. If `h` is already an expression containing `none`, it can be simplified, but only in ways that do not alter its meaning. E.g. if `h` is `calc(none - 10)`, `calc(h + 20)` can become `calc(none + 10)` but can also just stay `calc(calc(h - 10) + 20)` or `calc(h - 10 + 20)`.
- Interpolation operations (`color-mix()`, `calc-mix()`, gradients etc) _resolve_ `none` to the other component if the other component is not `none`-containing. If the other component is `none`-containing, they resolve to a `calc-mix()` expression containing both values. E.g. interpolating between a chroma of `none` and a chroma of `clamp(.1, none, .2)` at 50% would produce `calc-mix(50%, none, clamp(.1, none, .2))`. If this color is later interpolated with a color that has a chroma of 0.15, the `none`s would become 0.15, so the component would become `calc-mix(50%, 0.15, clamp(.1, 0.15, .2))` = 0.15.
- Authors should also be able to specify things like `min(50, none, 70)` directly.

Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/10211 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Monday, 15 April 2024 19:54:52 UTC