- From: Guillaume via GitHub <sysbot+gh@w3.org>
- Date: Sat, 15 Jun 2024 11:57:57 +0000
- To: public-css-archive@w3.org
[Converting HWB to sRGB](https://drafts.csswg.org/css-color-4/#hwb-to-rgb) produces `NaN` when whiteness is `-Infinity` or `+Infinity` (produced by a math function) or blackness is `-Infinity`.
For example, the current version of Chrome (126) serializes `rgb(NaN, NaN, NaN)` from `hwb(0 calc(-infinity) 0)`. FF clamps whiteness and blackness before the conversion.
Serializing `hwb()` requires converting to `rgb()`, therefore resolving math functions (extracting their result) before, as noted in [14.1. Resolving sRGB values](https://drafts.csswg.org/css-color-4/#resolving-sRGB-values):
> For historical reasons, when `calc()` in sRGB colors resolves to a single value, the declared value serialises without the "calc(" ")" wrapper.
**Note:** `calc()` should be replaced with *a math function*.
CSS Color 4 then says:
> Also for historical reasons, when `calc()` is simplified down to a single value, the color values are clamped to `[0.0, 255.0]`.
But it does not require clamping `hwb()` channel values before conversion to `rgb()`.
I do not think `NaN` cases can be specifically handled in the conversion algorithm.
When whiteness/blackness is < 0 or > 100, the produced color is different depending on which of whiteness/blackness (line in FF) or RGB (like in Chrome) values are clamped:
```js
// whiteness < 0
$el1.style.color = 'hwb(90 -200 0)'
$el2.style.color = 'hwb(90 -100 0)'
$el3.style.color = 'hwb(90 -50 0)'
$el4.style.color = 'hwb(90 0 0)'
getComputedStyle($el1).color; // rgb(128, 255, 0) in FF, rgb(0, 255, 0) in Chrome
getComputedStyle($el2).color; // rgb(128, 255, 0) in FF, rgb(0, 255, 0) in Chrome
getComputedStyle($el3).color; // rgb(128, 255, 0) in FF, rgb(64, 255, 0) in Chrome
getComputedStyle($el4).color; // rgb(128, 255, 0) in FF and Chrome
// whiteness > 100
$el5.style.color = 'hwb(0 100 50)'
$el6.style.color = 'hwb(0 200 50)'
getComputedStyle($el5).color; // rgb(170, 170, 170) in FF and Chrome
getComputedStyle($el6).color; // rgb(170, 170, 170) in FF, rgb(204, 204, 204) in Chrome
```
When whiteness/blackness is < 0 and not clamped, the hue is shifted: `hwb(90 -100 0)` becomes `hwb(120 0 0)`.
When whiteness/blackness is > 100 and not clamped, the lightness is shifted: `hwb(0 200 50)` becomes `hwb(0 100 25)`.
Finally, when `(whiteness + blackness) > 1`, I am not sure I understand the current logic. If the algorithm should match the result of mixing paints, I do not understand why the produced color is not white when `(whiteness - blackness) > 100`, or black when `(blackness - whiteness) > 100`. `whiteness + blackness` should probably not be greater than `100`.
---
I am not sure I understand the reasons, the conditions, the timing, for clamping out of range values.
HSL is off topic but similar observations can be made:
- when saturation is > 100 and lightness < 0, eg. `hsl(0 200 -25)`, the hue and lightness are shifted: I would expect black, but I get `rgb(0, 64, 64)` in Chrome
- when saturation is > 100 and 0 < lightness < 100, eg. `hsl(90 200 25)`, the hue and lightness are shifted: I get `rgb(64, 191, 0)` in Chrome, which corresponds to `hsl(100 100 37.45)`
Currently, channel values that must be clamped are:
- RGB
- saturation at lower boundary
- chromaticity at lower boundary
- lightness of `ok?lab()` and `ok?lch()`
They must be clamped at parse time. They must not be clamped in a relative or origin color (and possibly in `color-mix()`, #10414).
For RGB, CSS Color 3 optionally requires gamut mapping, without defining how or when. CSS Color 4 required clamping at computed value time before.
For saturation, CSS Color 4 follows CSS Color 3, which requires clamping, without defining when, and lets UAs optionally gamut mapping other channel values (like RGB). CSS Color 4 required clamping saturation and lightness at computed value time before.
For chromaticity and lightness of `ok?lab()` and `ok?lch()`, CSS Color 4 required clamping at computed value time before.
If the reason for clamping RGB and saturation is backward compatibility, what are the reasons for clamping chromaticity and lightness of `ok?lab()` and `ok?lch()`?
--
GitHub Notification of comment by cdoublev
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/10368#issuecomment-2169392747 using your GitHub account
--
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config
Received on Saturday, 15 June 2024 11:57:58 UTC