How to Use CSS animation-composition
The CSS animation-composition property defines how an
element's animated keyframe values interact with its underlying base
styles or other running animations. By specifying one of three
values—replace, add, or
accumulate—developers gain precise control over whether an
animation completely overwrites an existing property value, stacks
alongside it, or mathematically combines with it. This guide explains
how each mode works, how they differ, and how to use them effectively in
modern web design.
The Problem It Solves
By default, CSS animations completely override any base styles
applied to an element for the targeted property. For example, if a base
class applies transform: translateX(50px) and an animation
defines transform: rotate(45deg), the translation is lost
during the animation because the rotation replaces it. Historically,
developers had to redefine the base styles inside every keyframe. The
animation-composition property solves this by allowing
keyframes to dynamically combine with an element's existing
properties.
The Three Composition Values
The animation-composition property accepts three keyword
values:
animation-composition: replace;
animation-composition: add;
animation-composition: accumulate;1. replace (Default
Behavior)
The replace value is the standard behavior of CSS
animations. The keyframe value replaces the underlying base property
value entirely.
.box {
transform: translateX(100px);
animation: spin 3s infinite;
animation-composition: replace;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}- Result: At the start of the animation,
translateX(100px)is replaced by the initial animation state. The element rotates, but the 100px translation is ignored.
2. add (Stacking
Values)
The add value appends the keyframe value to the
underlying base value, creating a composite list. The animated value
acts as an addition to the existing style chain from left to right.
.box {
transform: translateX(100px);
animation: spin 3s infinite;
animation-composition: add;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}- Result: The browser evaluates the final transform
as
transform: translateX(100px) rotate(360deg). The element maintains its original 100px offset while performing the rotation.
For space-separated or comma-separated properties (such as
filter or box-shadow), add
appends the animation values onto the existing list:
.card {
filter: blur(2px);
animation: brighten 2s infinite alternate;
animation-composition: add;
}
@keyframes brighten {
to {
filter: brightness(1.5);
}
}- Result: The computed filter becomes
filter: blur(2px) brightness(1.5).
3.
accumulate (Combining Values Mathematically)
The accumulate value combines the underlying value and
the animated value into a single, merged value whenever mathematically
possible. Instead of appending to a list, it performs an arithmetic
addition.
Consider an element that already has a blur filter applied:
.image {
filter: blur(5px);
animation: pulse-blur 2s infinite alternate;
animation-composition: accumulate;
}
@keyframes pulse-blur {
to {
filter: blur(10px);
}
}- Result: With
accumulate, the values merge arithmetically. At the end of the keyframe, the computed filter isfilter: blur(15px)(5px + 10px), rather than a stacked list of two separate blur functions.
The Difference
Between add and accumulate
The distinction between add and accumulate
is clearest when animating matching transform functions or multi-value
units:
- Using
addon identical transform functions: If the base style istransform: scale(2)and the keyframe istransform: scale(1.5),addproducestransform: scale(2) scale(1.5). The browser multiplies the matrices sequentially. - Using
accumulateon identical transform functions: Usingaccumulateon the same styles combines them arithmetically. The basescale(2)and animatedscale(1.5)sum their delta from the default state, resulting in a singlescale(2.5).
If the values cannot be combined arithmetically—such as combining a
rotate() with a
scale()—accumulate falls back to behaving like
add.
Application in Multiple Animations
The animation-composition property can also accept a
comma-separated list to handle multiple animations applied to a single
selector:
.element {
transform: translateX(50px);
animation:
slide 2s infinite,
pulse 1s infinite;
animation-composition: add, accumulate;
}In this setup, the slide animation stacks onto the base
transform using add, while the pulse animation
combines with the preceding states using accumulate. This
granular control allows complex, layered UI micro-interactions without
writing redundant CSS rules.