-
Notifications
You must be signed in to change notification settings - Fork 690
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
[css-color] Computing lch/lab to srgb with lightness = 0% or 100% #8794
Comments
The requirement to force colors to white or black by setting chroma/hue and a/b to zero when the lightness is 0 or 100 during the conversion can seem jarring in these situations, and I wonder if such requirements are better suited in gamut mapping and not conversion. These requirements in conversion are essentially gamut mapping these extreme "lightness" cases, but nothing else. I believe the idea is that when lightness is at these extremes, said lightness will essentially overpower any contribution to the color that chroma and hue are providing making them meaningless. While I don't disagree with this assertion, I do wonder if conversion is the right place to make these corrections. I don't know if browsers intentionally or unintentionally have left out this CSS requirement, but I know that I've currently left out this requirement in my color library as the results feel surprising. Granted, my goal isn't necessarily to strictly follow what CSS does, but to simply handle CSS color formats as inputs and outputs. Consider the example below. We interpolate between We can see that just clipping, as browsers currently do, gives a consistent transition, but does not resolve these extremes to white or black. With the added requirement by CSS (which browsers are not currently doing), we see that we get a jarring discontinuity in color. Lastly, when using proper gamut mapping, we will naturally resolve these extreme cases as black or white and provide a more consistent transition to them. For the above reasons, I wonder if such resolutions of colors should be left solely up to the gamut mapping method being used. I do admit that there may be non-obvious reasons (to me) why CSS desires these additions. |
I think the underlying issue is that there are two versions of the spec. https://drafts.csswg.org/css-color/#specifying-lab-lch makes no mention of
That seems pretty clear to me that this is a special case. Testcases are missing in wpt. |
Yes the /TR version needs to be republished, there have been a lot of changes since the last one |
That might indeed be a better way to express the requirement. Assuming that gamut mapping (rather than naive clipping) happens for display, so that there is consistency in color appearance on displays of different gamuts. |
Looks like I misread the spec, sorry for the noise. The latest version doesn't say a and b are powerless, but that they must be set to 0, which is even stronger.
|
I second that, I believe conversion may not be right place to make these corrections. Furthermore, adding this requirement also contradicts with the following test: Could we change the spec to make it more clear? |
If the powerless logic in CSS is to be followed, I imagine that the Lab value for this would be I also don't think it completely harmless if we consider some interpolation cases. Consider this example where we attempt to interpolate only lightness of two Lab colors in Oklab. In the first example, we do not enforce the CSS powerless requirement during conversion and get a colored gradient (gamut mapping the final results), but if we use the CSS requirement, we get a grayscale interpolation. If we impose this requirement now, will it be relaxed when/if we get true gamut mapping (if not in level 4 maybe Level 5)? Or once it is in the spec, will it remain for backwards compatibility? Do we even care about the above interpolation use cases? While I personally think it makes sense to keep a separation between conversion and gamut mapping/clipping, this may not be CSS's goal, but I figured it is worth bringing up as a talking point before a decision is forever in place. In reality, this is probably a very minor issue. |
I agree, the discontinuity (L=0 vs. L=0.01, etc) is not helpful and the desired result would occur because of gamut mapping to the display in any case. |
Yes, the discontinuity of powerlessness has been brought up before. It's an unfortunate but unavoidable consequence, if you want to keep solving the problems that powerlessness is designed to solve (which is: don't hallucinate a component value that the author didn't and couldn't state in the original color space, just because a conversion shifted the color into a space where that component requires a value. |
Powerlessness of hue angle applies to all achromatic colors though, not just white and black. |
It seems that we agree that forcing the color to be black or white is not a desired user experience. Could we change the spec to reflect it? The current spec is as follows:
Could we change to something like:
I found lab(100%, 0, 0)/lch(100%, 0, 0) maps to white and lab(0%, 0, 0)/lch(0%, 0, 0) maps to black is explained later in the spec: (https://drafts.csswg.org/css-color/#specifying-lab-lch)
|
Is this to say that this powerlessness is really only an issue for conversions into the color spaces with lightness as a component? It's an interesting thing to try to design around, in my opinion, because there are many different whites that a user could be trying to express:
Also, what is to be done for intermediate values? Should
|
It is primarily an issue for conversions into a space with hue as a component.
I get
I'm getting
I get |
So is there a particular reason to also single out For the conversions, I'm just using chromium. What are you using? I'm getting almost exactly the same results in FF and Safari, with the exception of the https://codepen.io/mysterydate/pen/QWJJXOX For the implementation, should |
I am a bit confused. As For Thank you again for the clarification. |
It displays as white on screen because the lightness is 100. |
(I suspect there may be an assumption that |
Looks like the language in the spec changed again? """ So this would imply that the mapping should be done at used value time? |
Yes, this doesn't affect the computed value and we are avoiding clamping so that colors round-trip without loss. So yep, used value. |
Looking around this thread for points which have not already been addressed, or where the spec has not already been updated, I wanted to comment on
There aren't many different whites; sRGB white is the same as P3 white or rec2020 white, or media white in any SDR colorspace that has a D65 whitepoint.
Problems arise when chromatic adaptation comes into play, because now we are computing corresponding colors (a color that looks the same as the original color did, after our eyes have adapted to a new white point). This affects Given those caveats,
So the chromatic adaptation steps there have introduced a small error, but only visible in the numbers at 8 significant figures. Looking now at the Yes, because there was agreement that those colors displaying as white or black was a result of gamut mapping to the display so the spec changed to say that explicitly.
Yes. See step 7 in converting colors. The only stage in color conversions where gamut mapping happens is now for actual display (previously it was also used for conversions into HSL or HWB); all other stages of color conversions aim to preserve lossless round-tripping. |
so we return
But if we try to display that color it is out of gamut on an sRGB screen (indeed, on any screen) so we convert to Oklch for gamut mapping: |
This inaccuracy is due to a less precise Bradford inverse matrix. I go into more details here: color-js/color.js#352 (comment). I plan to issue a PR for color.js when I get a chance. |
The Oklab matrices are now 64bit accurate and were copied over from this color.js PR Bradford matrices were updated as a result of |
According to the spec, "The first argument specifies the CIE Lightness, L. This is a number between 0% or 0 (representing black) and 100% or 100 (representing white), Values less than 0% or 0 must be clamped to 0% at parsed-value time; values greater than 100% or 100 are clamped to 100% at parsed-value time"
With the current color conversion algorithm, both Chrome and Safari are still using a and b (or c and h) when lightness is at 0% or 100%. example: https://jsfiddle.net/orah1qd2/ lab(0, 100, 100) is showing as some shade of red instead of black.
I am trying to understand how the color conversion works for lightness at 0% or 100%.
Thank you for helping.
The text was updated successfully, but these errors were encountered: