Re: [csswg-drafts] [css-color-4] Channel clipping breaks author expectations, especially when using 'perceptually uniform' spaces (#9449)

Alright, and here are some replies to @ccameron-chromium’s comments (I think he’s been the only one pushing back on gamut mapping in this exceedingly long thread?).

## On baking a gamut into Oklab/Oklch 

It seems very clear to me that NOT baking a specific gamut into CSS is the way to go. It is historically very common to think that we've reached the end of a certain technology, and things are not possibly going to evolve much, and yet, they nearly always do. We already had to revamp CSS once because we assumed a given gamut would be sufficient for all uses and yet it wasn't, so let's please not make that mistake again. 

The argument that once display technology improves sufficiently we may be forced to do so is a little weird: we may have to do a bad thing in the future, so let's do it already? How about we cross that bridge when we get to it?

## Better visibility of system status: dev tools to the rescue?

On that note, another realization is that there should _really_ be a way for authors to read the actual displayed value of a color, though I suspect that will be deemed too much of a fingerprinting vector.

At the very least, dev tools can do a lot here. Since they have elevated permissions, they could show what color is actually displayed even if the web platform does not have a way to get this information. Also, they can prevent this by showing which of the major gamuts a color belongs to, with suitable styling to warn for colors outside P3 and even more strongly for colors outside Rec.2020.

## On prevalence and type of use cases

Having used `oklch()` myself, *extensively*, it is very clear to me that even with relatively small values, it is pretty easy to get out of gamut. Even at the same C value, different L, H values can make it swing *wildly* out of gamut, and the only C value where this doesn't happen is exceedingly low.

The promise of color spaces like Oklch is to be able to create entire design systems from a single color (here’s [my very WIP attempt](https://live-colors.verou.me/), and here is [someone else's](https://twitter.com/ardovalexey/status/1649962359711236098)). This cannot be realized without reasonable gamut mapping. Yes, once you’re out of gamut perceptual uniformity has left the chat, but that does not excuse throwing component orthogonality out of the window as well.

Saying that authors should "just take care" of staying in gamut is like arguing against viewport-relative units and media queries by saying that authors should "just" take care to use fixed widths that fit the viewport. Neither the output device gamut is fixed, not even the colors themselves, as @mirisuzanne explained [here](https://github.com/w3c/csswg-drafts/issues/9449#issuecomment-1907576834). 

@ccameron-chromium 
> Yeah, that's kinda where I'm going ... "if the author is using srgb or display-p3, they probably are going to give meaningful color values, but if the author is using oklch or oklab, then they are likely to hand me something physically impossible".

In my experience, when authors specify colors in RGB spaces, it's usually one of the following:
- [UX Stockholm Syndrome](https://lea.verou.me/blog/2023/minimalist-affordances/#ux-stockholm-syndrome): Many authors are still more familiar with RGB than polar spaces, and end up using those. However, this has its limitations once you get beyond fixed color tokens. Nobody sane would specify relative colors in RGB spaces, and interpolation (`color-mix()`, `in <colorspace>`) in gamma-encoded spaces has well known problems.
- Circularity: Authors have tried device independent color spaces, saw how nonsensical the output was in Blink and ran away. So in essence, you’re pointing out a problem that _you_ created and using it to further justify what you did!
- For hex codes, they have copied the color from a color picker, but I don't think that applies to functional notations as much.

From a user experience perspective, specifying colors in a format that is designed around monitor hardware rather than the way humans conceptualize color is a huge antipattern. And any color model that is *not* designed around hardware is going to have this problem, by definition.

@ccameron-chromium 
> With color-mix() it's usually safe (if the two endpoints that you are mixing are both within in a given gamut, then, because the gamuts are mostly-most-of-the-time convex, the line segment between them will still be in the gamut).

Nope. Not when interpolating in polar spaces 😁 

Example:`oklch(90% .2 100)` [is within the P3 gamut](https://colorjs.io/apps/gamut-mapping/?color=oklch%2890%25+.2+100%29), but `oklch(90% .2 80)` is [not even in Rec.2020](https://colorjs.io/apps/gamut-mapping/?color=oklch%2890%25+.2+80%29)! It's not even a huge hue difference, only -20.
This is not uncommon, nor did it take me long to find an example of this, it happens all the time when interpolating in polar spaces. I’ve even seen a delta of 1 take a color from P3 to (marginally) outside Rec.2020!

@ccameron-chromium 
> Problem 1: Author specifies colors that the author intends (that is, they have observed the color they are specifying on some existing screen), but those colors are outside of the gamut of the target device.
> 
> There exists a whole ecosystem of solutions to this. The oldest and best known would for the screen to use an ICC profile with a perceptual rendering intent, the more modern methods would be to specify metadata such as Mastering Display Color Volume (aka MDCV [SMPTE ST 2086](https://ieeexplore.ieee.org/document/8353899)) or Content Color Volume (aka CCV [ISO/IEC 23008-2](https://www.iso.org/standard/85457.html)).

One thing to keep in mind is that a lot of gamut mapping algorithms in the literature focus on preserving *relationships* between colors in an image, whereas for the CSS use cases, preserving individual color characteristics is more important (with the priorities being hue > lightness > chroma).

@ccameron-chromium 
> A space like `okhsv` and `okhsl` would be a better match for this problem.

Unfortunately these, [as currently specified](https://bottosson.github.io/posts/colorpicker/), are also sRGB-bound.
But I'd definitely agree with the sentiment that we need better color spaces! But that is orthogonal to making the ones we have work reasonably.

## Overall

@ccameron-chromium, I think you have some very specific use cases in mind that are driving your narrative. That would explain why you think matching `<canvas>` colors is top priority. There are certainly use cases where this is crucial, but the vast majority of CSS color use cases have nothing to do with `<canvas>`. As a design principle, niche use cases should not degrade the experience for the majority. For the use cases where this matters, `<canvas>` could handle this via a context attribute (either to enable gamut mapping, or restrict gamut to a specific space, or whatever).

I would also not be opposed to a CSS property to disable gamut mapping for a subtree, as long as the default value is that gamut mapping is enabled.

I am however, *very* strongly opposed to things like…

> The resolution that I want us to get to has the following shape:
> 
> * Bake gamut mapping (say, to `rec2020`) into `oklab` and `oklch`
>   * That's what option in chrome://flags does... approximately.
> * Consider adding `oklab-srgb`, `oklab-p3`, and `oklab-rec2020` variants (if valuable)
>   * If so, make the default interpolation space be the `oklab-rec2020` variant
>   * Make `oklab` map to one of these
> * Bake a similar (or maybe same?) gamut mapping to `lab` and `lch` spaces.
> * Consider re-introducing the restriction of parameters being in `[0,1]` for the RGB/XYZ spaces.
>   * (I'm agnostic on this -- there's a place for extended spaces, but maybe they should be explicitly named)
> 
> I think that this space has solutions to all of the issues we've discussed here. Except the "but we might need to update the spec in 10 years" issue, which I think is fine.

In this entire thread, plenty of actual authors, as  well as people working with authors on a daily basis, have been trying to explain to you, repeatedly, that good gamut mapping is needed. **This is as much a human factors problem, as a technical problem .** I would go as far as to call this reply tone deaf.

I have never raised a formal objection in my 11 years around here, but **I will formally object to any of the proposed resolutions above**.

Instead…

> I intersect the line of constant L and H with a polyhedral approximation of the Rec2020 gamut. This was supposed to be the first step towards getting within the neighborhood of convergence for Newton or Halley iteration,

…I think that’s the right direction: exploring ways to make gamut mapping both produce better quality results, and doing it faster, so that performance does not force us into clipping, alongside opt-outs for the few cases that do not benefit from it. So I’m glad you’re working on this!

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


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

Received on Wednesday, 14 February 2024 16:43:22 UTC