Skip to content

[css-color] updated computed value tests#60620

Open
romainmenke wants to merge 8 commits into
web-platform-tests:masterfrom
romainmenke:fix-color-tests--courageous-eastern-lowland-gorilla-8aa4239938
Open

[css-color] updated computed value tests#60620
romainmenke wants to merge 8 commits into
web-platform-tests:masterfrom
romainmenke:fix-color-tests--courageous-eastern-lowland-gorilla-8aa4239938

Conversation

@romainmenke

@romainmenke romainmenke commented Jun 14, 2026

Copy link
Copy Markdown
Contributor
  • fix cases where none was dropped
  • use correct serialization

Comment thread css/css-color/parsing/color-computed-color-mix-function.html Outdated
Comment on lines +117 to +118
fuzzy_test_computed_color(`color-mix(in hsl, hsl(120deg 10% 20%) 0%, hsl(30deg 30% 40%) 0%)`, `color(srgb 0.33 0.36 0.24 / 0)`);
fuzzy_test_computed_color(`color-mix(in hsl, hsl(120deg 10% 20% / .4) 0%, hsl(30deg 30% 40% / .8) 0%)`, `color(srgb 0.37222222 0.41111111 0.25555556 / 0)`);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +213 to +214
fuzzy_test_computed_color(`color-mix(in hwb, hwb(120deg 10% 20%) 0%, hwb(30deg 30% 40%) 0%)`, `color(srgb 0.575 0.7 0.2 / 0)`);
fuzzy_test_computed_color(`color-mix(in hwb, hwb(120deg 10% 20% / .4) 0%, hwb(30deg 30% 40% / .8) 0%)`, `color(srgb 0.55833333 0.66666667 0.23333333 / 0)`);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +311 to +312
fuzzy_test_computed_color(`color-mix(in lch, lch(10% 20 30deg) 0%, lch(50% 60 70deg) 0%)`, `lch(30 40 50 / 0)`);
fuzzy_test_computed_color(`color-mix(in lch, lch(10% 20 30deg / .4) 0%, lch(50% 60 70deg / .8) 0%)`, `lch(36.66666667 46.66666667 50 / 0)`);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +409 to +410
fuzzy_test_computed_color(`color-mix(in oklch, oklch(10% 20 30deg) 0%, oklch(50% 60 70deg) 0%)`, `oklch(0.3 40 50 / 0)`);
fuzzy_test_computed_color(`color-mix(in oklch, oklch(10% 20 30deg / .4) 0%, oklch(50% 60 70deg / .8) 0%)`, `oklch(0.36666667 46.66666667 50 / 0)`);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

["hwb(120 30% 50% / 0.5)", "rgba(77, 128, 77, 0.5)"],
["hwb(120 30% 50% / 50%)", "rgba(77, 128, 77, 0.5)"],
["hwb(none none none)", "rgb(255, 0, 0)"],
["hwb(none none none)", "hwb(none none none)"],

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://drafts.csswg.org/css-color-4/#css-serialization-of-srgb

However, the legacy color syntax with comma separators cannot represent none. If the value has at least one missing color component, the serialization form is chosen to preserve those components as the none keyword, based on the color function of the declared value:

For hwb() values, the value is serialized using the modern (whitespace-separated) hwb() syntax, with a slash before the alpha component when present. The function name is "hwb" in ASCII lowercase. The hue is serialized as a canonicalized in degrees, the whiteness and blackness as s, and the alpha (included only if non-unity or missing) per the alpha rules; any missing component is serialized as the none keyword.

#container {
container-type: inline-size;
color: rgb(255, 0, 0]);
color: rgb(255, 0, 0);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

}

// Ensure that `calc` values work with dynamically changing relative units (slighly different alpha values to make test harness not complain about duplicate tests).
// Ensure that `calc` values work with dynamically changing relative units (slightly different alpha values to make test harness not complain about duplicate tests).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

Comment on lines -130 to 134
fuzzy_test_computed_color(`rgb(from rgb(none none none) r g b)`, `color(srgb 0 0 0)`);
fuzzy_test_computed_color(`rgb(from rgb(none none none / none) r g b / alpha)`, `color(srgb 0 0 0 / 0)`);
fuzzy_test_computed_color(`rgb(from rgb(20% none 60%) r g b)`, `color(srgb 0.2 0 0.6)`);
fuzzy_test_computed_color(`rgb(from rgb(20% 40% 60% / none) r g b / alpha)`, `color(srgb 0.2 0.4 0.6 / 0)`);
fuzzy_test_computed_color(`rgb(from rgb(none none none) r g b)`, `color(srgb none none none)`);
fuzzy_test_computed_color(`rgb(from rgb(none none none / none) r g b / alpha)`, `color(srgb none none none / none)`);
fuzzy_test_computed_color(`rgb(from rgb(20% none 60%) r g b)`, `color(srgb 0.2 none 0.6)`);
fuzzy_test_computed_color(`rgb(from rgb(20% 40% 60% / none) r g b / alpha)`, `color(srgb 0.2 0.4 0.6 / none)`);
fuzzy_test_computed_color(`color-mix(in srgb, rgb(from rebeccapurple none g b), rebeccapurple)`, `color(srgb 0.4 0.2 0.6)`);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://drafts.csswg.org/css-color-4/#css-serialization-of-srgb

However, the legacy color syntax with comma separators cannot represent none. If the value has at least one missing color component, the serialization form is chosen to preserve those components as the none keyword, based on the color function of the declared value:

For rgb() and rgba() values (the only sRGB form in this list whose syntax accepts none; hex colors, named colors, system colors, deprecated-colors, and transparent have no parametric syntax and so never have missing color components), the value is serialized as a color() function in the srgb color space rather than as the modern space-separated form of rgb(), even though that form would also accept none: "color(srgb" followed by a single space, followed by a space-separated list of the three non-alpha components serialized as s in the [0, 1] reference range (or as none if missing), followed (only if the alpha is non-unity or missing) by " / " and the alpha component (serialized per the alpha rules, or as none if missing), followed by ")".

// Testing non-sRGB origin colors (no gamut mapping will happen since the destination is not a bounded RGB color space).
fuzzy_test_computed_color(`lch(from color(display-p3 0 0 0) l c h / alpha)`, `lch(0 0 0)`);
fuzzy_test_computed_color(`lch(from lab(0.7 45 30) l c h / alpha)`, `lch(0.7 54.08327 33.690067)`);
fuzzy_test_computed_color(`lch(from color(display-p3 0 0 0) l c h / alpha)`, `lch(0 0 none)`);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hue is powerless and becomes missing when converting color(display-p3 0 0 0) to lch

@weinig

weinig commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

I would prefer if the precision changes were done separately, but otherwise, looks good to me. It's good timing too, since I was about to update WebKit to preserve hsl()/hwb() serialization.

fuzzy_test_computed_color(`rgb(from rgb(none none none / none) r g b / alpha)`, `color(srgb 0 0 0 / 0)`);
fuzzy_test_computed_color(`rgb(from rgb(20% none 60%) r g b)`, `color(srgb 0.2 0 0.6)`);
fuzzy_test_computed_color(`rgb(from rgb(20% 40% 60% / none) r g b / alpha)`, `color(srgb 0.2 0.4 0.6 / 0)`);
fuzzy_test_computed_color(`rgb(from rgb(none none none) r g b)`, `color(srgb none none none)`);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one I am not sure of.

Relative color syntax says that r, g, and b are <number>s. I don't think that can include none, thus, none should be converted to 0 here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Except, now I see there is text elsewhere, https://drafts.csswg.org/css-color-5/#relative-syntax, that now states: "The component keywords return a <number>, or none;".

I am not certain this is well enough specified to make this change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Importantly, if they can be none, calc() is completely undefined (see this ongoing issue w3c/csswg-drafts#10211), and I think it would be weird for the component symbols to work alone one way, and in calc() another.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The component keywords return a <number>, or none;

This was added exactly to clear up any confusion about allowing and preserving missing components in relative colors.

w3c/csswg-drafts#10151 (comment)

https://drafts.csswg.org/css-color-5/#ex-serial-rcs-nested-none

This example does contradict that however :/
I'll submit a PR to update that example in the spec.


But also see: w3c/csswg-drafts#10211 (comment)

None is preserved in calculations involving css math functions
When interpolating between two none-containing values, the result is a calc-mix() expression preserving the none keywords in both values

No spec edits were made in support of those resolutions.
And there also no concrete examples of what of any of that means.

I think the intention is to defer changing none into zero for as long as possible.

But at the same time it is also invalid for authors to write an explicit none in a math function.

rgb(from red calc(none + 5) 0 0) /* invalid -> explicit none in calc */
hsl(from white calc(h + 5) 0 0) /* valid -> `h` is powerless and becomes missing */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I seem to be behind the times :).

That all seems quite confusing and unclear in the current spec language.

The last I remember, the issue was that analogous components made this hard because when doing a color conversion, but I see the analogous component part of the spec has changed a lot and now has an analogous set concept. Much for me to implement in WebKit I guess :).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the behavior of color conversion between analogous components that have different ranges, like conversion of the lightness component for an lch to oklch conversion, defined anywhere?

For example, what would happen in a case like:

color-mix(in lch, lch(50% 25 90), oklch(from oklch(none 0.25 90) calc(l + 0.1) c h))

What happens when the oklch value, which after RCS resolution will be oklch(calc(none + 0.1) 0.25 90), gets converted into the interpolation colorspace? Does the calc(none + 0.1) the a scaling factor applied to it somehow?

@romainmenke romainmenke Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had and still have the same concerns. Raising those seems to have stalled the edits around preserving missing component in calc.

I personally don't think there is a strong use case for preserving missing components in calc and later filling those in when there is some interpolation in an unknown colorspace. I think this will surprise authors a lot more than that it will act as a feature. But maybe I am wrong about this :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example 58 has been updated to clarify that none must be preserved when serializing RCS.

I'd like to separate the question of what to do in calc() from the changes in this PR.

Are there changes I can make to this PR to move forward with it?

@weinig weinig left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Temporarily removing my approve while we discuss.

@svgeesus

Copy link
Copy Markdown
Contributor

I would prefer if the precision changes were done separately

Yes.

I agree we need to discuss a bit more and possibly do clarifying spec edits before accepting these changes.

@romainmenke

Copy link
Copy Markdown
Contributor Author

I will reduce the precision of the expected values so they match what was previously there.

@weinig

weinig commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Looks like there are still a bunch of changes that just altering the precision.

@romainmenke

Copy link
Copy Markdown
Contributor Author

I haven't pushed any changes yet :)

@svgeesus svgeesus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall this looks good to me now.

@svgeesus svgeesus requested a review from weinig June 19, 2026 11:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants