[csswg-drafts] [css-color] How to handle out-of-bounds legacy srgb values? (#10087)

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

== [css-color] How to handle out-of-bounds legacy srgb values? ==
Consider this testcase:

```html
<!DOCTYPE html>
<style>
#a { width: 200px; height: 200px; animation: a 2s -1s paused linear(0, -1, 1) }
#b { width: 100px; height: 100px; animation: b 2s -1s paused linear }
#c { width: 100px; height: 100px; animation: c 2s -1s paused linear }
@keyframes a {
  from { background-color: rgb(75, 0, 0) }
  to { background-color: rgb(0, 255, 0) }
}
@keyframes b {
  from { background-color: inherit }
  to { background-color: rgb(0, 255, 0) }
}
@keyframes c {
  from { background-color: black }
  to { background-color: rgb(0, 255, 0) }
}
</style>
<div id="a">
  <div id="b"></div>
  <div id="c"></div>
</div>
<pre><script>
document.styleSheets[0].cssRules[5].cssRules[0].style.backgroundColor = getComputedStyle(a).backgroundColor;
document.writeln(getComputedStyle(a).backgroundColor);
document.writeln(getComputedStyle(b).backgroundColor);
document.writeln(getComputedStyle(c).backgroundColor);
</script>
```

The background of `#a` is the interpolation between `rgb(75, 0, 0)` and `rgb(0, 255, 0)`. The easing function is `linear(0, -1, 1)`, so at 50% the input progress value is -1. Both colors are legacy, so we interpolate in srgb instead of oklab, producing a color as such:
 - Color space: srgb
 - Legacy flag: yes
 - Red: 150
 - Green: -255
 - Blue: 0

But of course, `G = -255` is out of bounds, so the painted background is `rgb(150, 0, 0)`.

However, on Gecko and Blink, the computed value still has this `G = -255`, as we can observe in `#b`. The background color of `#b` is the 50% linear interpolation between the value inherited from `#a` and `rgb(0, 255, 0)`. This serializes as `rgb(75, 0, 0)`, which means that the inherited value has `G = -255`.

The problem is, what do we get if we serialize the computed value of `#a`? Since `G = -255` is out-of-bounds, browsers just clamp and serialize as `rgb(150, 0, 0)`.

But of course, when `#c` does the same as `#b`, but interpolating from the provided `rgb(150, 0, 0)`, then it produces `rgb(75, 128, 0)`.

WebKit seems to adjust the computed value of `#a`, because `#b` produces `rgb(75, 128, 0)` just like `#c`.

So, questions:
 - Why does `color-mix()` prevent me from picking a percentage outside of the 0-100% range, if I can do the mix with arbitrary values via animations/transitions (but it's much less convenient)?
 - Should Gecko and Blink adjust the computed value to avoid out-of-bounds problems?
 - If not, should we change the serialization so that it doesn't become a different color? Maybe serialize with `color-mix()`?

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


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

Received on Thursday, 14 March 2024 20:28:42 UTC