CSS @keyframes At-Rule

The @keyframes at-rule defines the stages of a CSS animation by specifying how an element's styles change over time. It uses the from and to keywords or percentage values to control properties such as opacity, position, color, and transforms.

@keyframes Syntax

@keyframes animation-name {
  from {
    property: value;
  }
  to {
    property: value;
  }
}

The at-rule begins with @keyframes, followed by a name that identifies the animation. Inside the block, keyframe selectors specify the styles applied at different stages.

The from keyword represents the beginning of an animation, while to represents its end.

For example, the following animation changes an element from transparent to fully visible.

@keyframes fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

Defining keyframes does not start an animation. The animation must be assigned to an element using animation-name and an animation duration.

How @keyframes Works

A CSS animation changes property values between defined keyframes. The browser calculates the intermediate values for properties that support animation.

@keyframes slide-right {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(100px);
  }
}
.box {
  animation: slide-right 2s ease-in-out;
}

The element moves horizontally from its original position to 100px to the right over two seconds.

The animation shorthand connects the element to the named keyframes and specifies the duration and timing function.

Animations can run automatically when styles are applied, without JavaScript or user interaction.

Keyframe Selectors

Keyframe selectors identify specific points in an animation. They can use keywords or percentages.

Selector Description
from Beginning of the animation, equivalent to 0%.
to End of the animation, equivalent to 100%.
0% Starting point of the animation.
50% Halfway point of the animation.
100% Ending point of the animation.

Percentages must be between 0% and 100%, inclusive. Values outside this range and numbers without a percent sign are invalid keyframe selectors.

Using Percentage Keyframes

@keyframes change-color {
  0% {
    background-color: #0056b3;
  }
  50% {
    background-color: #28a745;
  }
  100% {
    background-color: #dc3545;
  }
}

This animation changes from blue to green and then to red.

Keyframes do not need to appear in percentage order. The browser arranges them according to their positions in the animation.

Grouping Keyframe Selectors

@keyframes pulse {
  0%, 100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.15);
  }
}

Comma-separated selectors apply the same declarations at multiple points. In this example, the element returns to its original size at the end of each cycle.

Animation Properties

The @keyframes at-rule defines an animation's stages. Animation properties determine how that animation runs on an element.

Property Description
animation-name Specifies the name of the keyframes to use.
animation-duration Sets the duration of one animation cycle.
animation-timing-function Controls how the animation progresses between keyframes.
animation-delay Specifies how long to wait before the animation begins.
animation-iteration-count Sets how many times the animation repeats.
animation-direction Controls whether the animation runs forward, backward, or alternates.
animation-fill-mode Controls whether keyframe styles apply before or after the animation.
animation-play-state Specifies whether the animation is running or paused.
animation Shorthand property for configuring multiple animation settings.

Applying an Animation

.animated-box {
  animation-name: slide-right;
  animation-duration: 2s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-direction: alternate;
}

The animation runs for two seconds in each direction and repeats continuously.

The default animation duration is 0s, so a positive duration is normally required to see a time-based animation.

Multiple Keyframes

An animation can contain several stages and animate multiple properties at the same time.

@keyframes move-and-fade {
  0% {
    transform: translateX(0);
    opacity: 0;
  }
  50% {
    transform: translateX(60px);
    opacity: 1;
  }
  100% {
    transform: translateX(120px);
    opacity: 0.5;
  }
}
.box {
  animation: move-and-fade 3s linear;
}

The element moves to the right while its opacity changes at different points during the animation.

Each animatable property is evaluated independently. A property does not need to appear in every keyframe.

Properties that cannot be animated do not produce smooth interpolation between values.

Missing and Duplicate Keyframes

An animation does not need explicit 0% and 100% keyframes. When either endpoint is missing, the browser uses the element's computed property values to establish the missing endpoint.

@keyframes fade-away {
  to {
    opacity: 0;
  }
}
.message {
  opacity: 1;
  animation: fade-away 2s;
}

The animation starts from the element's computed opacity of 1 and ends at 0.

Duplicate Keyframe Selectors

When the same percentage appears more than once within a single @keyframes rule, declarations at that percentage are combined according to their source order.

@keyframes highlight {
  50% {
    opacity: 0.5;
  }
  50% {

    background-color: #ffcc00;
  }
}

Both declarations contribute to the 50% keyframe because they affect different properties. If the same property is declared more than once at that percentage, the later applicable declaration wins.

Duplicate Animation Names

If multiple @keyframes rules use the same name, the last matching rule is used. Separate keyframe definitions with the same name are not merged.

@keyframes fade {
  to {
    opacity: 0.5;
  }
}
@keyframes fade {
  to {
    opacity: 0;
  }
}

The second fade definition replaces the first.

Animation Timing

Animation timing functions control the rate of change between keyframes. They can be applied to an entire animation or specified for individual keyframe intervals.

@keyframes horizontal-movement {
  0% {
    transform: translateX(0);
    animation-timing-function: ease-in;
  }
  50% {
    transform: translateX(100px);
    animation-timing-function: ease-out;
  }
  100% {
    transform: translateX(200px);
  }
}

The first interval uses ease-in, while the second uses ease-out.

A timing function declared at a keyframe controls the interval beginning at that keyframe. A timing function at the final keyframe does not affect an interval within that animation cycle.

The animation-timing-function property can also be declared on the animated element to provide the default timing behavior.

Accessibility

Continuous or large animations can be distracting for some users. The prefers-reduced-motion media feature allows animations to be reduced or disabled when a user requests less motion.

@keyframes slide-in {
  from {
    transform: translateX(-40px);
    opacity: 0;
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}
.notice {
  animation: slide-in 600ms ease-out;
}
@media (prefers-reduced-motion: reduce) {
  .notice {
    animation: none;
  }
}

The animation runs normally unless the user's system preference requests reduced motion. In that case, the notice appears without the animation.

Animations should not be the only way important information is communicated.

@keyframes Example

The following example creates a pulsing blue box using three keyframes. The animation changes its size and opacity before returning to the original appearance.

<div class="pulse-box">CSS Animation</div>
@keyframes pulse-box {
  0%, 100% {
    transform: scale(1);
    opacity: 1;
  }
  50% {
    transform: scale(1.1);
    opacity: 0.65;
  }
}
.pulse-box {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 180px;
  height: 100px;
  background-color: #0056b3;
  color: #fff;
  animation: pulse-box 2s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
  .pulse-box {
    animation: none;
  }
}

Play in Editor

The box gradually increases in size, becomes partially transparent, and returns to its original appearance. The animation repeats every two seconds unless reduced motion is requested.

Browser Support: The @keyframes at-rule is widely available across modern browsers. Some advanced animation features have separate compatibility requirements. See Can I Use? for browser compatibility information.

Specifications

The @keyframes at-rule is defined in CSS Animations Module Level 1. The specification describes animation names, keyframe selectors, interpolation, and how animation declarations are applied.

CSS Animations Module Level 1