Additive Animations in CSS
The following is supported in the latest Firefox, Edge, and Chrome (and also Safari Technology Preview). Yay.
What happens when you have two simultaneous animations in CSS that modify the same property?
transform value can be set at a given time, so only one of the translations will occur (the last one in the
animation list wins, so for this example it is the vertical animation with
The Web Animations API allows us to mix up this behavior through the introduction of the
First, we can make an equivalent animation in the WAAPI as the previous CSS example:
The default behavior remains the same, so this code will do the exact same as the CSS, where only the vertical translation will occur.
It does let us start playing with a new option, however, called the
composite property. Its default value is
'replace' which is the behavior we have discussed so far, where a value on a property is replaced by a newer animation that comes along and tries to modify the same property.
If we change the second animation to add a
composite: 'add' option, we tell it to add the value of this animation to whatever the current state of that property is.
Now, instead of replacing the value defined by the first animation, it adds our new value. For
transform which has a syntax that accepts a list of transform functions, adding means appending the new transform functions to the end of the existing list. The
filter property is another list-based property that will allow you to keep appending new values to the list of functions.
For properties that are not lists, add behaves slightly differently, but in line with what you may expect. Properties that accept any number-based valu (such as lengths, percentages, or raw numbers) will add the numbers together. So if you have two animations affecting
opacity, the resulting visual opacity will be the sum of the current values of
opacity in each animation.
The same goes for moving an item 20px + 30px with margin left (not the most performant way to move an object, but it demonstrates length usage)… if the animations both run at the same time, with the same duration and in the same direction, the end result will be a movement of 50px.
Bringing it to CSS
Currently, there is no way to specify this same behavior in CSS, though there have been discussions to add it. That doesn’t mean our CSS animations cannot take advantage of this option today.
getAnimations() method on elements (including the
document) you can fetch all the WAAPI animations, CSS animations, and CSS transitions that are active on the element. More importantly, we can modify the keyframes, timing options, or
composite property on any animation returned. So all of a sudden our animations (even our CSS ones) can be updated at any time (even while they are running).
All that to say… you can use the magic of
Once you have an element, you can call
getAnimations() on it, iterate through the array of animations, and update each one to update the
composite property. If you need to only add it to certain animations in the list, you can check the
animation.animationName property for CSS Animations or use other methods to determine which animation is which.
This can also go along with the
animationstart and other events to make sure you are updating the property at an appropriate time. These events do not contain an
Animation object in the handler, but they do return identifying information such as the
animationName. So we can cross reference this
event.animationName with the
animationName found in the
getAnimations() list for CSS Animations to pinpoint and update any animation we are looking for.