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-color-4][css-values-4][web-animations-1] Behavior of additive animations of color properties is unclear #7793

Closed
weinig opened this issue Sep 25, 2022 · 9 comments

Comments

@weinig
Copy link

weinig commented Sep 25, 2022

While going to fix the following WPT tests in WebKit:

- web-animations/animation-model/animation-types/accumulation-per-property-001.html
- web-animations/animation-model/animation-types/accumulation-per-property-002.html
- web-animations/animation-model/animation-types/addition-per-property-001.html
- web-animations/animation-model/animation-types/addition-per-property-002.html

which had failing test cases for additive and accumulative animations of color properties, I ran across a few underspecified areas that could use some clarification:

  1. How should color addition work in general? CSS Value 4 says:

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

This works for the rectangular color types, but how should the hue component of the cylindrical color types be added? Should it differ based on what hue interpolation mode is in effect? (this is not currently a problem, as there is no syntax to ask an animation to use a cylindrical interpolation method, but that seems like it is only a manner time).

Also, how does addition of the alpha channel work? Should it overflow if the two values add up to more than 1?

  1. How should color component overflow and gamut mapping work?

The model for additive animation of colors as assumed by the tests noted above assume that overflow of the sRGB gamut will clip, rather than do gamut mapping. For example, this subtest:

    test(t => {
      const idlName = propertyToIDL(property);
      const target = createTestElement(t, setup);
      target.style[idlName] = 'rgb(128, 128, 128)';
      const animation = target.animate(
        {
          [idlName]: ['rgb(255, 0, 0)', 'rgb(0, 0, 255)'],
        },
        { duration: 1000, composite }
      );
      testAnimationSamples(animation, idlName,
                           [{ time: 0,   expected: 'rgb(255, 128, 128)' },
                            // The value at 50% is interpolated
                            // from 'rgb(128+255, 128, 128)'
                            // to   'rgb(128,     128, 128+255)'.
                            { time: 500, expected: 'rgb(255, 128, 255)' }]);
    }, `${property} supports animating as color of rgb() with overflowed `
       + ' from and to values');

assumes that the overflow of one component (for instance from's red component, which ends up being 128+255) is just clamped. This is a bit out of line with the current status quo, which would likely have this gamut mapped.

  1. What criteria should be used to determine if the legacy gamma-encode sRGB interpolation should be used? For gradient, it seemed relatively clear that one could just check if any color stop used a non-legacy color syntax, and switch to OKLab. But there are numerous ways to specify keyframe values for animations, and it is unclear whether we would want all of them to use legacy syntax or just the two we are actively interpolating between.

I know the use of legacy interpolation is a may condition in the CSS Color 4 spec, so perhaps this is not something the editors want to clarify. If that is the case, we should make sure that WPT tests are appropriately relaxed for multiple implementations.

@svgeesus
Copy link
Contributor

svgeesus commented Oct 4, 2022

The whole issue of additive CSS, opened in 2017, is still being discussed.

Additive animation makes sense for things like lengths but seems less valuable for color (I guess, in RGB spaces, adding or subtracting a constant offset on a per-component basis is a way to crudely increase or decrease the lightness, if you don't care about the hue changing wildly).

Good question about what to do about hue, if additive animation takes place in a polar space. I feel I need to better understand what the use cases are for additive animation of colors, to understand how that should behave. Note that premultiplication in polar spaces is already defined, at least.

@LeaVerou
Copy link
Member

LeaVerou commented Oct 4, 2022

Btw here is a demo of additive animation today: https://codepen.io/leaverou/pen/NWMzmoV

That should definitely not be in CSS Values, it belongs in Color, not sure if we can still add it to Color 4 or whether it would need to go into Color 4.

The prose also needs editing, this is way too vague. In which premultiplied space? E.g. what do we do when adding these:

  • Animation 1: LCH color transitioning to sRGB color in Lab
  • Animation 2: HSL color transitioning to OKLab color in OkLCH

In which space do we add their components??
It seems reasonable it would be either Lab or OkLCH since colors are converted to these spaces throughout their interpolation. But which one? And indeed, what do we do for <angle> values?

I guess the most obvious, but potentially less useful thing to do would be to pick the color space of the first color, and just naively add arguments. Is there something better we could do?

@svgeesus
Copy link
Contributor

svgeesus commented Oct 4, 2022

That should definitely not be in CSS Values, it belongs in Color, not sure if we can still add it to Color 4

Agree it belongs in Color 4.

In which space do we add their components??

The one they are animating or transitioning in.

@LeaVerou
Copy link
Member

LeaVerou commented Oct 4, 2022

In which space do we add their components??

The one they are animating or transitioning in.

My understanding is this is an operation that involves multiple animations, which could be interpolating in entirely different color spaces.

@svgeesus
Copy link
Contributor

svgeesus commented Oct 5, 2022

My understanding is this is an operation that involves multiple animations, which could be interpolating in entirely different color spaces.

Yes, you are right; and the current spec text for adding colors assumes all colors are resolved to sRGB.

So (by analogy with what we did for color interpolation) we need some 'host syntax' wording and then, if host does not specify:

  • colors add in OKLab (premultiplied, per-component)
  • all legacy colors may add in sRGB

@flackr
Copy link
Contributor

flackr commented Nov 24, 2022

Since composite: add is still relatively new, it may not be too late to rethink what adding colors mean. With transforms we append transform lists rather than add matrix components because that allows you to combine some new transform with the already existing one. With colors, I think it would be more useful (and more analogous to transforms) if adding colors implied what would happen if I put the new color on top of the old one. E.g. for opaque colors you just get the new color, but for translucent colors it would be as if that color was composited on top of the old color.

@birtles does this seem in line with the intent of additive compositing?

Then you could add an animation like:

@keyframes pulse {
  0% { background-color: rgba(0,0,0,0.2); }
  100% { background-color: rgba(255,255,255,0.2); }
}
.flashing {
  animation: pulse 1s infinite alternate;
  animation-composite: add;
}

To make an element's background alternate getting a bit darker and lighter.

@birtles
Copy link
Contributor

birtles commented Nov 25, 2022

Certainly that particular example with translucent colors seems very useful. However, I don't know enough about color to know what would be most useful in the general case.

Two considerations that might help frame the question though:

  1. If we were later to introduce !add (as has been proposed in [css-cascade] Additive CSS #1594) then what would we want to happen for content such as the following?

    .thing {
      background-color: yellow;
    }
    .thing.-special {
      background-color: blue !add;
    }
  2. If we ever want to map SVG/SMIL animations onto Web Animations (as was one of the original goals of Web Animations, and something we considered doing in Gecko at one point), then we might want to keep the component-wise addition as a possible behavior since SVG defines color addition in those terms.

@flackr
Copy link
Contributor

flackr commented Nov 25, 2022

  1. If we ever want to map SVG/SMIL animations onto Web Animations (as was one of the original goals of Web Animations, and something we considered doing in Gecko at one point), then we might want to keep the component-wise addition as a possible behavior since SVG defines color addition in those terms.

This could make sense for composite: accumulate to do this kind of addition - other than that adding colors only supports lightening use cases and IMO doesn't really make much sense in OKLab which is the default interpolation space. I agree that there's value in supporting this as a possible behavior.

@tabatkins tabatkins removed the css-values-4 Current Work label Oct 23, 2023
@svgeesus
Copy link
Contributor

svgeesus commented Jan 24, 2024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants