Skip to content
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-values-4][css-color] Addition of <color> is way underspecified. #8576

Closed
svgeesus opened this issue Mar 13, 2023 · 13 comments
Closed

[css-values-4][css-color] Addition of <color> is way underspecified. #8576

svgeesus opened this issue Mar 13, 2023 · 13 comments
Labels
Closed Accepted by CSSWG Resolution Commenter Satisfied Commenter has indicated satisfaction with the resolution / edits. css-values-4 Current Work

Comments

@svgeesus
Copy link
Contributor

svgeesus commented Mar 13, 2023

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:

Addition of <color> is likewise defined as the independent addition of each component as a <number> in premultiplied space.)

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.

--one: color(display-p3 0.3 0.6 0.2 / 0.5);
--two: oklch(0.5 0.2 140);

What happens when I add --one and --two, and why.

@svgeesus svgeesus added the css-values-4 Current Work label Mar 13, 2023
@tabatkins
Copy link
Member

tabatkins commented Mar 13, 2023

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.

@svgeesus
Copy link
Contributor Author

Okay if it is just completeness then there are two obvious ways forward:

  • specify something that is easy and good, because there is no web compat issue (colors add in premultiplied oklab)
  • specify that colors do not add.

@tabatkins
Copy link
Member

Agenda+ to decide which of the two options above we should do.

@svgeesus
Copy link
Contributor Author

svgeesus commented Apr 6, 2023

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]
  • add oklab components: [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
Copy link
Member

@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.

@atanassov atanassov changed the title Addition of <color> is way underspecified. [css-values-4][css-color] Addition of <color> is way underspecified. May 30, 2023
@tabatkins
Copy link
Member

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.

@css-meeting-bot
Copy link
Member

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
The full IRC log of that discussion <emeyer> chris: The original text about adding color was from the sRGB days and it assumes consistent color spaces
<emeyer> …It turns out nothing actually depends on this
<emeyer> …We could say colors don’t add, or we pick something good since there’s no backwards compatibility issue
<emeyer> …I propose the latter
<emeyer> …so I have everything I need to add to the spec
<dbaron> (you're sure smil animation doesn't depend on this?)
<fserb> q+
<emeyer> TabAtkins: I’m unclear when it would be useful to do an additive animation to a color, I suspect we should just go the simplest route and say colors don’t add
<flackr> q+
<fserb> q-
<emeyer> chris: That is simple and easy, yeah
<emeyer> TabAtkins: Additive transforms make more sense, but colors seem a lot more integrated and meaningful
<fserb> +1 to tabatkins
<Rossen_> ack flackr
<emeyer> flackr: I commented on another issues that adding colors should be treated as composition of that color
<TabAtkins> composition certainly makes more sense than component addition
<TabAtkins> tho *which* composition is always a question
<emeyer> …This to me feels like the thing you’re trying to express when adding a color to another color
<chris> q+
<emeyer> …I think that interpretation solves the color-space question
<florian> q?
<emeyer> …Because it goes to the color space of whatever you’re compositing onto
<fantasai> https://www.w3.org/TR/web-animations-1/#effect-composition
<Rossen_> ack fantasai
<fantasai> enum CompositeOperation { "replace", "add", "accumulate" };
<emeyer> fantasai: The addition of values is defined in web animations and there’s a composite operation that lets you change how you’re doing it
<fantasai> https://www.w3.org/TR/web-animations-1/#the-compositeoperation-enumeration
<emeyer> …That’s where this whole definition came from
<emeyer> …It seems like replacement is not what’s intended
<Rossen_> ack chris
<emeyer> …I don’t know that defining this as replacement is what we want, long-term
<TabAtkins> I think the Web Anim use of the word "composited" is unrelated to the "composition" that flackr just mentioned
<emeyer> chris: What was described as compositing on top of is interpolation, which is defined a sentence earlier
<emeyer> …So in one case, we point off to the interpolation definition, and the other case, we say you can’t do it
<fantasai> TabAtkins, yes, but follow that link
<fantasai> It's switching between replace/add/accumulate
<emeyer> TabAtkins: Rob is describing compositing, not interpolating
<emeyer> chris: The only difference is the color space you do the compositing in, but it’s still interpolation
<fserb> q+
<TabAtkins> fantasai, yes, that's still not what flackr is talking about
<fantasai> no, it's not
<emeyer> flackr: You do get weird interpolations with opacities involved
<fantasai> I'm saying, that's what's defining that replacement and addition should be different
<TabAtkins> they're different *if* you define an addition operation. if you don't, they're the same
<emeyer> fserb: I think we shoudl step back and focus on the first question
<fantasai> There was an assertion that the definition of addition isn't used
<emeyer> …My feeling is that even if we don’t have a use case right now, we should lean toward not adding
<fantasai> and it is, in WA1
<emeyer> …Just in case we find reasons to do it in the future
<TabAtkins> it's not used *in practice*, chris said
<emeyer> chris: I tend to agree that if we don’t have a use case, we shouldn’t spec it
<lea> agreed that not adding is easier to extend in the future vs some random addition algorithm
<flackr> q+
<emeyer> …I don’t think a lot of thought went into this bit of the spec because it didn’t get exercised
<emeyer> fantasai: Are you saying there’s no use case, or that there’s no room for it in CSS?
<emeyer> chris: That there’s no use case
<fserb> ack fserb
<fantasai> s/no room for it/no way for the definition to get used/
<Rossen_> ack fserb
<Rossen_> ack flackr
<emeyer> flackr: I do think there are use cases, like modifying underlying color by some amount as with transforms
<emeyer> …I think the risk of not doing tsomething now is that it could become a breaking change in the future
<emeyer> …I think if we assume they don’t add, then the result is you get the second color, as it replaces the first
<emeyer> chris: I believe that’s correct
<emeyer> Rossen_: So this is really a what-if, there’s no use case
<emeyer> …So what do we do?
<emeyer> …We can remove it from the spec until someone comes up with a use case
<emeyer> …We could leave it as is
<lea> q?
<emeyer> flackr: I’m very much against the current behavior
<emeyer> chris: Same here
<emeyer> lea: Agreed
<TabAtkins> it wasn't underspecified at the time, fwiw - back when it was written colors were specified as sRGB
<emeyer> Rossen_: What if we bring all of it back to the whiteboard, and maybe find some use cases in the meantime?
<TabAtkins> clearlly not something we want to do now
<emeyer> …How does that sound?
<fserb> I'm good with this too
<emeyer> chris: So we’re effectively resolved they don’t add now, and can change it later
<emeyer> TabAtkins: Plus add a note saying we’d like use cases
<emeyer> fantasai: And that we might change it in the future
<emeyer> Rossen_: Objections to the note and warning?
<emeyer> plinss: I’m a little concerned about not doing things when we don’t have use cases
<fserb> q+
<emeyer> …What’s the justification for not doing it?
<emeyer> …Authors might come up with cool stuff once a possibility is out there
<emeyer> TabAtkins: There’s a lot of ways of defining addition, and without use cases, it’s an arbitrary choice
<flackr> add rgb(0, 0, 0, 0.1) /* darken */
<emeyer> …If we decide that for now we don’t add at all, authors can still get what they want by doing their own blending
<emeyer> …We don’t have an obvious behavior to bless here
<fantasai> +1
<emeyer> fserb: There are a lot of axes you can change colors on, none of which are “add"
<emeyer> Rossen_: I didn’t hear objections, and peter’s concern seems addressed
<TabAtkins> flackr: reasonable to argue for the "just composite it" in the issue, if you do think we should do that
<emeyer> RESOLVED: Colors don’t add; add a note asking for use cases and a warning specifying we might change in the future

@flackr
Copy link
Contributor

flackr commented May 31, 2023

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.

@plinss
Copy link
Member

plinss commented May 31, 2023

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.

@tabatkins
Copy link
Member

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.

@plinss
Copy link
Member

plinss commented May 31, 2023

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).

@tabatkins
Copy link
Member

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.

@ydaniv
Copy link
Contributor

ydaniv commented Jun 1, 2023

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Closed Accepted by CSSWG Resolution Commenter Satisfied Commenter has indicated satisfaction with the resolution / edits. css-values-4 Current Work
Projects
None yet
Development

No branches or pull requests

6 participants