Closed svgeesus closed 1 year ago
It sounds like this text was written when
<color>
was always an sRGB value so you add the red, green and blue components.
That is indeed the case, yes.
As for why you want to add the color, I think it's just that you can add things, and colors seem addable, so you can add colors. I don't think there's a use-case for it.
Okay if it is just completeness then there are two obvious ways forward:
Agenda+ to decide which of the two options above we should do.
For the example given in the original post, the results would be:
1. (colors add in premultiplied oklab)
because
color(display-p3 0.3 0.6 0.2 / 0.5);
is oklab(0.603 -0.15 0.118 / 0.5)
which when premultiplied is `[0.3015, -0.075, 0.509]'oklch(0.5 0.2 140)
is oklab(0.5 -0.15 0.129)
which is the same when premultiplied [0.5, -0.15, 0.129]
[0.8015, -0.225, 0.638]
but wait, if I was interpolating then I would interpolate the alpha. But I am adding so do I add them? Interpolate them?
Not clear how to un-premultiply here and 8.1.1. Combination of <color>
doesn't say, even for sRGB.
@tabatkins any clues? I guess that adding rgba(32, 64, 128, 50%)
and rgba(128, 64, 32, 50%)
produces 50% alpha not 100% right?
2. specify that colors do not add
color(display-p3 0.3 0.6 0.2 / 0.5);
because V&U 4 Combining Values: Interpolation, Addition, and Accumulation says
If a value type does not define a specific procedure for addition or is defined as not additive, its addition operation is simply Vresult = Va.
@tabatkins any clues?
Honestly I suspect that the alphas are intended to be added too (and then clamped). I dunno what you'd do otherwise.
Not to argue one way or the other on whether adding colors even makes sense, but if we do add them, I think non-premultiplied is actually the only correct answer. An addition animation is fundamentally different from a normal animation; you write it as a delta around 0, rather than as an absolute animation between two values. (Adding two normal animations together generally gives nonsense results, I think.) So you need a meaningful zero to start from for each value being added; premultiplied makes the zero alpha have extra effects and generally ruins things.
As for "why would you add colors", I guess being able to, say, pulse a color's lightness independent of whatever else its color might be doing is in theory something useful to do? But I think it's a pretty rare thing to do, and almost certainly better to fold into the original animation (via color-mix() or something, for example). So I think "colors don't add" is still a very reasonable option to decide on.
The CSS Working Group just discussed [css-values-4][css-color] Addition of `<color>` is way underspecified.
, and agreed to the following:
RESOLVED: Colors don’t add; add a note asking for use cases and a warning specifying we might change in the future
My intuition is that we should treat adding colors as the result of composing the new color on top of the old. This would allow effects such as:
@keyframes shade {
0% { background: rgba(0, 0, 0, 0);
100% { background: rgba(0, 0, 0, 0.2);
}
.selected {
animation: shade 500ms infinite alternate add;
}
Which would darken whatever the element's background was. You could similarly do a lighten effect - but this is technically possible with the current behavior where we add components whereas darkening is not. I realize darkening could also be done with a filter but there may be reasons for wanting it just on the background color.
Composing the new color on top of the old is equivalent to interpolating the colors as @svgeesus mentioned during the call.
I agree that we should interpolate the colors and thought of a use case. I have two animations that move an element and shift its color at the same time (fairly common in individual animations), let's say one makes the color brighter, the other shifts its hue. When both animations run on the same element, the positions add, and the colors shouldn't switch to changing discretely or start ignoring one or the other animation. Not interpolating the color seems like a surprising (and undesired) behavior.
Not equivalent to interpolation. Compositing might invoke the same math as interpolation (dunno what the math is off the top of my head), but it's still a distinct process from "standard" interpolation and has different effects (the interpolation % would be relative to the top-layer's alpha, for example, and the resulting alpha is not determined by interpolation at all). Plus it's not feature-matching with real interpolation; you can't do a hue-space compositing like you can with interpolating.
The math for src-over compositing in RGB is (SourceChannel * alpha) + (DestChannel + (1 - alpha)) (where alpha is 0 to 1), which looks like interpolation to me, but I accept it likely gets more interesting in other color spaces and with gamma correction, etc. But that's not my main point, and I was only echoing ChrisL there.
My point is that I think interpolating the colors during additive animations is the right approach after all (regardless of the actual math and if it's equivalent to composition or not). There are many cases where people animate something else and color together. When multiple of those animations run together, the 'something else' properties often make sense for additive animations. In that case, all the color animations should still apply, and the colors should still animate in a way that's not going to surprise the author (like only using one of the color animations or changing the color discretely).
The math for src-over compositing
Right, that uses the mathematical structure of interpolation, but it's not the interpolation process that animation refers to, a la "mix these two colors, with a progress % of X". That's what I mean; it's still a completely distinct process.
My point is that I think interpolating the colors during additive animations is the right approach after all
No, interpolation (that is, real, normal interpolation) is absolutely not what you want. It's not even well-founded - when writing an additive animation you're specifying the values as deltas rather than absolute values, so they're totally different data types than what you specify in a normal animation. (They just use the same unit, so they're easily confuseable.)
Like, specifying a wiggle transform might involve animating from transformX(-10px)
to transformX(10px)
repeatedly; you don't want to actually interpolate that with a normal slide-in animation from transformX(0)
to transformX(1000px)
. Same applies to colors. We don't have a delta type for colors, but I suppose compositing gives you a similar result.
I think colors can't add because they are simply points in color space, unlike filters (also in color) and transforms (in R^3) which are vectors. So trying to force them into same operations is bound to be awkward.
Perhaps we should reconsider the early attempt in #2875 to specify color-transform functions that only affect a specific property and not a complete filter on the entire element/background?
As for use-cases, I know authors are currently using SVG filters for these things (which only work with filter
), but in this case having something like translate()/rotate()/transfer()
on component-level could be really nice.
One example is duotone effect, which currently requires grayscale(1)
+ extra layer with -blend-mode: mupltiply
+ extra layer with -blend-mode: screen
.
It probably doesn't help that I don't really understand why one would want to add
<color>
s (as opposed to, say, adding lengths which is obviously useful in an animation or transition). That said, this sentence in V&U4 on Combination of<color>
seems underspecified:The color space in which addition happens is unspecified. It sounds like this text was written when
<color>
was always an sRGB value so you add the red, green and blue components.What happens when I add
--one
and--two
, and why.