animation

Avatar of Ryan Trimble
Ryan Trimble on

DigitalOcean provides cloud products for every stage of your journey. Get started with $200 in free credit!

The animation property in CSS can be used to animate many other CSS properties such as color, background-color, height, or width. Each animation needs to be defined with the @keyframes at-rule which is then called with the animation property, like so:

.element {
  animation: pulse 5s infinite;
}

@keyframes pulse {
  0% {
    background-color: #001F3F;
  }
  100% {
    background-color: #FF4136;
  }
}

Each @keyframes at-rule defines what should happen at specific moments during the animation. For example, 0% is the beginning of the animation and 100% is the end. These keyframes can then be controlled either by the shorthand animation property, or its eight sub-properties, to give more control over how those keyframes should be manipulated.

Sub-properties

  • animation-name: declares the name of the @keyframes at-rule to manipulate.
  • animation-duration: the length of time it takes for an animation to complete one cycle.
  • animation-timing-function: establishes preset acceleration curves such as ease or linear.
  • animation-delay: the time between the element being loaded and the start of the animation sequence (cool examples).
  • animation-direction: sets the direction of the animation after the cycle. Its default resets on each cycle.
  • animation-iteration-count: the number of times the animation should be performed.
  • animation-fill-mode: sets which values are applied before/after the animation.
    For example, you can set the last state of the animation to remain on screen, or you can set it to switch back to before when the animation began.
  • animation-play-state: pause/play the animation.
  • animation-composition: specifies how keyframes composite when animations affect the same property.

These sub-properties can then be used like so:

@keyframes stretch {
  /* declare animation actions here */
}

.element {
  animation-name: stretch;
  animation-duration: 1.5s; 
  animation-timing-function: ease-out; 
  animation-delay: 0s;
  animation-direction: alternate;
  animation-iteration-count: infinite;
  animation-fill-mode: none;
  animation-play-state: running;
  animation-composition: add;
}

/*
  is the same as:
*/

.element {
  animation: 
    stretch
    1.5s
    ease-out
    0s
    alternate
    infinite
    none
    running;
}

Here’s a full list of which values each of these sub-properties can take:

animation-timing-functionease, ease-out, ease-in, ease-in-out, linear, cubic-bezier(x1, y1, x2, y2) (e.g. cubic-bezier(0.5, 0.2, 0.3, 1.0))
animation-durationXs or Xms
animation-delayXs or Xms
animation-iteration-countX
animation-fill-modeforwards, backwards, both, none
animation-directionnormal, alternate
animation-play-statepaused, running
animation-compositionaccumulate, add, replace

Multiple steps

If an animation has the same starting and ending properties, it’s useful to comma-separate the 0% and 100% values inside @keyframes:

@keyframes pulse {
  0%, 100% {
    background-color: yellow;
  }
  50% {
    background-color: red;
  }
}

Multiple animations

You can comma-separate the values to declare multiple animations on a selector as well. In the example below, we want to change the color of the circle in a @keyframe whilst also nudging it from side to side with another.

.element {
  animation: 
    pulse 3s ease infinite alternate, 
    nudge 5s linear infinite alternate;
}

Composite operations

Defining a property in CSS also sets what is considered the underlying value of the property. By default, keyframe animations will ignore the underlying value, as they only consider the effect values defined within the animation. Keyframes create a stack of effect values, which determines the order in which the animation renders to the browser. Composite operations are how CSS handles the underlying effect combined with the keyframe effect value.

We have a few options for combining animation effects.

Replace

The default value for the animation-composition property, replace will replace the underlying property value in favor of the effect value defined in keyframes.

.toast {
  /* Underlying values */
  opacity: 1;
  transform: translateY(0);
  animation: fade-in 0.25s ease-in;
  
  /* Replace is the default value */
  /* for animation-composition
  animation-composition: replace; */
}

@keyframes fade-in {
  0% {
    /* Effect values */
    opacity: 0;
    transform: translateY(50px);
  }
}

Add

The add composite operation will be added to the underlying property value with the current keyframe’s effect value. Some properties may be added together differently depending on the type of value. Transforms, for example, stack effect values on top of the underlying effect value.

.toast {
  /* Underlying values */
  transform: translateY(20px);
  animation: fade-in 0.25s ease-in;
  
  /* Adds the underlying value to */
  /* the current effect value */
  animation-composition: add;
}

@keyframes fade-in {
  0% {
    /* Effect values */
    transform: translateY(50px);
  }
}

This would composite by adding the effect value of translateY(50px) on top of the underlying translateY(20px).

/* Start of animation */
transform: translateY(20px) translateY(50px);

/* End of animation */
transform: translateY(20px) translateY(0);

Using animation-composition: add when animating colors offers an interesting effect. For example, instead of replacing an underlying background-color property value with the keyframe’s effect value, the color type values are combined, creating new colors.

.toast {
  /* Underlying values */
  background-color: #3498db;
  animation: changeColor 2s ease-out infinite;
  animation-composition: add;
}

@keyframes changeColor {
  0% {
    /* Effect values */
    background-color: #2ecc71;
  }

  100% {
    background-color: #c0392b;
  }
}

Accumulate

The accumulate and add composite operations may seem rather similar as both combine property values together, however they differ in interesting ways.

.toast {
  /* Underlying values */
  transform: translateX(20px);
  animation: slideX 0.25s ease-in;
  
  /* Combines similar underlying values */
  /* with the current effect value */
  animation-composition: accumulate;
}

@keyframes slideX {
  0% {
    /* Effect values */
    transform: translateX(50px);
  }
}

In this example, the underlying transform: translateX(20px); will combine with the keyframe’s effect value of transform: translateY(50px);to become transform: translateX(70px); at the start of the animation.

/* Start of animation */
transform: translateX(70px);

/* End of animation */
transform: translateX(20px);

This effectively isn’t different than animation-composition: add, where accumulate really helps is when animations affect multiple properties.

.toast {
  /* Underlying values */
  transform: translateX(20px) rotate(45deg);
  animation: fade-in 0.25s ease-in;
  
  /* Combines the underlying value */
  /* with the currently effect value */
  animation-composition: accumulate;
}

@keyframes fade-in {
  0% {
    /* Effect values */
    transform: translateX(50px);
  }
}

For this example, the underlying transform property contains translateY as well as rotate, however the keyframe’s effect value only animates the translateX value. The accumulate composite operation will combine translateX(20px) and translateX(50px) into translateX(70px), causing the element to animate only on the x-axis.

/* Start of animation */
transform: translateX(70px) rotate(45deg);

/* End of animation */
transform: translateX(20px) rotate(45deg);

Performance

Animating most properties is a performance concern, so we should proceed with caution before animating any property. However, there are certain combinations that can be animated safely:

  • transform: translate()
  • transform: scale()
  • transform: rotate()
  • opacity

Which properties can be animated?

MDN has a list of CSS properties which can be animated. Animatable properties tend to colors and numbers. An example a non-animatable property is background-image.

Browser support

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

Desktop

ChromeFirefoxIEEdgeSafari
4*5*10125.1*

Mobile / Tablet

Android ChromeAndroid FirefoxAndroidiOS Safari
1301304*6.0-6.1*

More information