Closed Bug 1293490 Opened 8 years ago Closed 2 years ago

Implement CSS animation-composition

Categories

(Core :: CSS Parsing and Computation, enhancement, P3)

enhancement

Tracking

()

RESOLVED FIXED
104 Branch
Tracking Status
firefox104 --- fixed

People

(Reporter: hiro, Assigned: boris)

References

(Blocks 3 open bugs, )

Details

(Keywords: dev-doc-complete)

Attachments

(3 files)

      No description provided.
Priority: -- → P3

Just received notice that Webkit will be looking to make this functionality available in H1 2022.

See Also: → 1748435
Blocks: 1732321
Severity: normal → --
Type: defect → enhancement
Attachment #9282880 - Attachment description: Bug 1293490 - Part 1: Implement CSS animation-composition in style system. → Bug 1293490 - Part 1: Implement CSS animation-composition longhand in style system.

Let nsAnimationManager takes animation-composition into account.

Note: This doesn't support animation-composition on each keyframes.

So we can use animation-composition in keyframes.

Blocks: 1778402
Assignee: nobody → boris.chiou
Status: NEW → ASSIGNED
Blocks: 1778407
Keywords: dev-doc-needed
Pushed by bchiou@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/9748d3bdef15
Part 1: Implement CSS animation-composition longhand in style system. r=emilio
https://hg.mozilla.org/integration/autoland/rev/df1148c8baf0
Part 2: Hook animation-composition to CSS animations. r=emilio
https://hg.mozilla.org/integration/autoland/rev/f745c54f8526
Part 3: Support animation-composition in keyframe at rules. r=emilio
Status: ASSIGNED → RESOLVED
Closed: 2 years ago
Resolution: --- → FIXED
Target Milestone: --- → 104 Branch

Hello, I am documenting this new 'animation-composition' property and finding it a little difficult to come up with suitable examples to demo this feature. (I am using Firefox 104.0b9 (64-bit)). I am looking for the following information and I'd really appreciate any help.

  1. Any real-world examples, real use cases where a web developer would want to use 'animation-composition' on a property across multiple animation keyframes?
  2. What are the likely properties for which the composite effect of add and accumulate can be used/will be useful?
  3. What is the difference between the values 'add' and 'accumulate' and what properties can I visually show the difference in their meanings?
  4. The spec says:

When specified in a keyframe, animation-composition defines the composite operation to use for each property specified in that keyframe until the next keyframe specifying each property.

Does this mean from their example that since @keyframes heartbeat has multiple values of scale, there would be a composite scale effect if the animation on the .heartbeat class styling is animation: heartbeat 0.3s 2s accumulate; ? I do not see any visual difference on testing.
5. I tried the examples from the spec here https://codepen.io/dipikabh/pen/xxWQzwa and here https://codepen.io/dipikabh/pen/NWYEYdz. I cannot make out the difference between the three - 'add', 'replace', or 'accumulate'.

Thanks,
Dipika

Flags: needinfo?(boris.chiou)

Hi, Dipika,

Thanks for documenting this CSS property. I tried my best to answer the questions below.

  1. Any real-world examples, real use cases where a web developer would want to use 'animation-composition' on a property across multiple animation keyframes?

Basically, I'm not sure if I'm a suitable person to answer this. However, if a web developer wants to combine the animation effect with its underlying value, animation-composition is the declarative way to define this, just like what we do for KeyframeEffect.composite. Perhaps you could check the answers below.

  1. What are the likely properties for which the composite effect of add and accumulate can be used/will be useful?

https://developer.mozilla.org/en-US/docs/Web/API/KeyframeEffect/composite provide an example by using filter, so perhaps we could use the same property in the MDN for animation-composition. Besides, I think transform property is also a good example to demo this. See the example in the 3rd answer.

  1. What is the difference between the values 'add' and 'accumulate' and what properties can I visually show the difference in their meanings?

First, the definition is in web animations spec: https://drafts.csswg.org/web-animations-1/#effect-composition, and in https://drafts.csswg.org/css-values-4/#combining-values
a) add: The effect value is added to the underlying value. For animation types where the addition operation is defined such that it is not commutative, the order of the operands is underlying value + effect value.
b) accumulate: The effect value is accumulated onto the underlying value. For animation types where the accumulation operation is defined such that it is not commutative, the order of the operands is underlying value followed by effect value.

It's a little bit tricky to see the difference between add and accumulate. transform property is a good example to see the difference.
See related wpt: https://searchfox.org/mozilla-central/source/testing/web-platform/tests/css/css-transforms/animation/transform-translate-composition.html
e.g.

@keyframes anim {
  from { transform: translateX(100px); }
  to { ... }
}
#target {
  transform: translateX(100px) rotate(90deg);
}

The underlying value is translateX(100px). So if we are using add, the "from" animation value is transform: translateX(100px) rotate(90deg) translateX(100px). If we are using accumulate, the "from" animation value is transform: translate(200px) rotate(90deg).

I also wrote an example in the 5th answer, so you can check the visual difference.

  1. The spec says:

When specified in a keyframe, animation-composition defines the composite operation to use for each property specified in that keyframe until the next keyframe specifying each property.

Does this mean from their example that since @keyframes heartbeat has multiple values of scale, there would be a composite scale effect if the animation on the .heartbeat class styling is animation: heartbeat 0.3s 2s accumulate; ? I do not see any visual difference on testing.

This means the keyframe-specific composite: https://drafts.csswg.org/web-animations-1/#keyframe-specific-composite-operation.
The example doesn't do this. I think the spec words mean something like this:

@keyframes anim {
  from { transform: translateX(100px); animation-composition: add; } // we define animation-composition inside @keyframes rule.
  to { transform: translateX(200px); }
}
#target {
  animation: anim 1s linear;
  animation-composition: accumulate;
  trasnform: translateX(100px) rotate(90deg);
}

So the first keyframe, we apply animation-composition: add, but the second keyframe, we don't define animation-composition the this keyframe, so we use the animation-composition of this element, i.e. accumulate here. (I didn't write an example for this, but you can update my example in codepen to see the difference after adding animation-composition in a keyframe.)

  1. I tried the examples from the spec here https://codepen.io/dipikabh/pen/xxWQzwa and here https://codepen.io/dipikabh/pen/NWYEYdz. I cannot make out the difference between the three - 'add', 'replace', or 'accumulate'.

I notice the preference is off by default, so first we have to enable the preference in Nightly: layout.css.animation-composition.enabled. Sorry about this. And I'm not sure these example are good to demo the visual difference between replace and accumulate. I saw a very minor difference between replace and add in these two cases.

However, I believe this cannot convince you, so I wrote another example for your reference: https://codepen.io/BorisChiou/pen/XWEyxXE

Thanks. :)

Flags: needinfo?(boris.chiou)
Blocks: 1785329

Thank you so so much, Boris! I really appreciate this info. Your examples have helped clarify a lot of concepts. The comments in WPT are useful for documentation purposes; thanks for sharing that! I do have a few follow-up questions:

  1. You mentioned that "the preference is off by default." Is that intended? I thought this feature would be available by default in 104 version. If it's behind a preference setting that needs to be turned true, I will need to document that.

  2. In your example explanation in 3 in the previous comment:

The underlying value is translateX(100px). So if we are using add, the "from" animation value is transform: translateX(100px) rotate(90deg) translateX(100px). If we are using accumulate, the "from" animation value is transform: translate(200px) rotate(90deg).

Did you mean that the underlying value is transform: translateX(100px) rotate(90deg)?

  1. In your keyframe-specific composite example, because there is no animation-composition in the second keyframe and you said that it will take 'accumulate' from the element, so will that be interpreted as: to { transform: translateX(200px); animation-composition: accumulate;}?
    I guess from the link you've shared https://drafts.csswg.org/web-animations-1/#keyframe-specific-composite-operation it seems to me that from { transform: translateX(200px) rotate(90deg); animation-composition: add;} , which has multiple properties, would mean that the composite operation is applied to translate and rotate.

  2. So in case of keyframe-specific composite, basically the animation is getting composite operation defined at the keyframe level instead of at the selector/element level?

  3. Some questions on your codepen example (thanks a ton for putting this together!!):

  • "replace" and "accumulate" seem to be working as expected - effect value replaces the underlying value so "from" in "replace" is transform: translateX(100px) and accumulate combines the effect so "from" in "accumulate" is transform: translateX(150px) rotate(90deg).
  • However, in the "add" case, "from" would be transform: translateX(50px) rotate(90deg) translateX(100px) . The second green box is rotated alright and seems to have moved 50px but it is moving from top to down - I was expecting it to move another 100px horizontally and animate horizontal move "to" 200px. Could you explain the animation-composition: add; behavior here?

Thanks a lot,
Dipika
(To make this less cumbersome and reduce the back-and-forth, would you mind connecting on Slack? I am in Germany, so 9 hours ahead.)

Flags: needinfo?(boris.chiou)

Oh! I think I get the "add" behavior in your codepen now. The move is happening top to down because the green box has rotated. So translateX behaves like translateY after the rotate. Is that correct?

(In reply to Dipika from comment #9)

  1. You mentioned that "the preference is off by default." Is that intended? I thought this feature would be available by default in 104 version. If it's behind a preference setting that needs to be turned true, I will need to document that.

Don't worry about this now. I am enabling it on Nightly (105): https://bugzilla.mozilla.org/show_bug.cgi?id=1785329. This bug just implemented this property, but the preference is still default by off on Nightly. So perhaps you can document that the feature is enabled by default on since Nightly 105. However it is still not ready to be enabled on beta and release version. animation-composition longhand is enabled only on Nightly.

  1. In your example explanation in 3 in the previous comment:

The underlying value is translateX(100px). So if we are using add, the "from" animation value is transform: translateX(100px) rotate(90deg) translateX(100px). If we are using accumulate, the "from" animation value is transform: translate(200px) rotate(90deg).

Did you mean that the underlying value is transform: translateX(100px) rotate(90deg)?

Oh yes. Sorry for the typo. I updated my example again and again when writing the the answer so I forgot to double-check it. Yes, the underlying value should be transform: translateX(100px) rotate(90deg).

  1. In your keyframe-specific composite example, because there is no animation-composition in the second keyframe and you said that it will take 'accumulate' from the element, so will that be interpreted as: to { transform: translateX(200px); animation-composition: accumulate;}?

Yes.

I guess from the link you've shared https://drafts.csswg.org/web-animations-1/#keyframe-specific-composite-operation it seems to me that from { transform: translateX(200px) rotate(90deg); animation-composition: add;} , which has multiple properties, would mean that the composite operation is applied to translate and rotate.

I'm a little bit confused about the question, so I try to list some possible answers here:

  1. Basically, animation-composition is not animatable (spec link), which means we don't have to worry about this in the keyframe. In other words, it is not related transform, and you will not see any animations on animation-composition. Basically, you can treat animation-composition as an extra attribute for this Keyframe so we can know this Keyframe uses add, instead of accumulate, in this example.
  2. Basically, each Keyframe has a composite operation type, i.e. replace, add, or accumulate. (note: you can use getKeyframes() to dump all the attributes for a specific Keyframe), so I think we can say, the composite operation is applied to "this keyframe". (i.e. All properties in this Keyframe).
  1. So in case of keyframe-specific composite, basically the animation is getting composite operation defined at the keyframe level instead of at the selector/element level?

The answer should be yes. the composite operation defined at the Keyframe has the higher priority.

An animation has a list of Keyframes, and each Keyframe has a composite operation (note: the DOM dictionary of Keyframe), so basically, when we see an animation for this element, we build the list of Keyframes for this animation. And when building a Keyframe, we choose the composite operation for this keyframe from 1) the keyframe-specific composite, 2) the animation-composition property for this element.

  1. Some questions on your codepen example (thanks a ton for putting this together!!):
  • "replace" and "accumulate" seem to be working as expected - effect value replaces the underlying value so "from" in "replace" is transform: translateX(100px) and accumulate combines the effect so "from" in "accumulate" is transform: translateX(150px) rotate(90deg).
  • However, in the "add" case, "from" would be transform: translateX(50px) rotate(90deg) translateX(100px) . The second green box is rotated alright and seems to have moved 50px but it is moving from top to down - I was expecting it to move another 100px horizontally and animate horizontal move "to" 200px. Could you explain the animation-composition: add; behavior here?

For add, We can remove animation-composition and change @keyframe rules to get an equivalent animation, like this:

@keyframes anim2 {
  from {transform: translateX(50px) rotate(90deg) translateX(100px);}
  to {transform: translateX(50px) rotate(90deg) translateX(200px);}
}
#target {
  width: 50px;
  height: 100px;
  background: green;
  border-radius: 10px;
  animation: anim2 2s linear infinite;
}

So Yes, from top to down is correct. Because it moves after it rotated 90deg. (All the transform operations can be converted into a matrix!)
You could check the conversion for the transform matrix: https://drafts.csswg.org/css-transforms/#mathematical-description. And a simple way is to write the the matrix of each operation, and do the matrix multiplication on them.

An easy way to know is: we rotate 90deg, so the x-axis of this element also rotates 90deg, and then translateX(...) becomes from top to down. (Another try to see what happens: change from rotate(90deg) to rotate(45deg), and its x-axis rotates 45deg now.) In conclusion, we cannot use the global x-axis for transform. :)

Anyway, it's also complicated to me. That's why transform property is a good example for animation-composition because the matrix multiplication is not commutative.

(To make this less cumbersome and reduce the back-and-forth, would you mind connecting on Slack? I am in Germany, so 9 hours ahead.)

Sure. My slack account is also boris (in Portland, Oregon, USA). Leaving comments here is also a good way because I have more time to think about the questions.

Flags: needinfo?(boris.chiou)

(In reply to Dipika from comment #10)

Oh! I think I get the "add" behavior in your codepen now. The move is happening top to down because the green box has rotated. So translateX behaves like translateY after the rotate. Is that correct?

Yes! We can not use global x-axis or y-axis to see the result. This is a matrix multiplication.

Thank you so much, Boris! All this has been extremely helpful, especially your clarifications to my queries.

I have now documented the animation-composition property. I am using your example in the doc :-). I have not elaborated on the keyframe-specific composite case in the doc for now, to first get the basics right.

I'd appreciate of you could take a look a the doc and point out if you see any glaring technical inaccuracies: https://github.com/mdn/content/pull/19848

Flags: needinfo?(boris.chiou)

(In reply to Dipika from comment #13)

Thank you so much, Boris! All this has been extremely helpful, especially your clarifications to my queries.

I have now documented the animation-composition property. I am using your example in the doc :-). I have not elaborated on the keyframe-specific composite case in the doc for now, to first get the basics right.

I'd appreciate of you could take a look a the doc and point out if you see any glaring technical inaccuracies: https://github.com/mdn/content/pull/19848

I notice there are some comment there already, so I will take a look later once you addressed those comments. :)

Flags: needinfo?(boris.chiou)

The documentation for animation-composition is now available: https://developer.mozilla.org/en-US/docs/Web/CSS/animation-composition.
Issue tracker that was used for this work: https://github.com/mdn/content/issues/18771

Thanks Boris for all your help with this feature.

Depends on: 1823862
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: