animation-direction selects the direction of each keyframe iteration. Alternate reverses every second iteration; it needs more than one iteration to show that change.
Compare normal and reverse
Both squares run once with linear timing. Normal moves left to right; reverse begins at the last keyframe and moves right to left.
HTML and CSS
HTML
<input class="run" id="run" type="checkbox" /><label for="run"
>Run the demonstration; uncheck to reset</label
>
<div class="stage">
<p>Normal</p>
<div class="box" aria-hidden="true"></div>
<p>Reverse</p>
<div class="box reverse" aria-hidden="true"></div>
</div>
CSS
@keyframes travel {
from {
transform: translateX(0);
}
to {
transform: translateX(100px);
}
}
.stage {
background: #eff6ff;
padding: 1rem;
}
.box {
width: 50px;
height: 35px;
background: #2563eb;
margin-block: 0.5rem;
}
label {
display: inline-block;
padding: 0.75rem;
}
.run:checked ~ .stage .box {
animation: travel 1s linear forwards;
}
.run:checked ~ .stage .reverse {
animation-direction: reverse;
}
@media (prefers-reduced-motion: reduce) {
.run:checked ~ .stage .box {
animation-name: none;
}
}
Edit HTML or CSS to update the preview as you type. Copy code snippet copies the selected tab. Preview spacing and font defaults are not included.
Run two alternating iterations
Alternate moves forward then back. With two iterations and forwards fill, the retained final position is the start, because the second iteration runs in reverse.
HTML and CSS
HTML
<input class="run" id="run" type="checkbox" /><label for="run"
>Run the demonstration; uncheck to reset</label
>
<div class="stage"><div class="box" aria-hidden="true"></div></div>
CSS
@keyframes travel {
from {
transform: translateX(0);
}
to {
transform: translateX(100px);
}
}
.stage {
background: #eff6ff;
padding: 1rem;
}
.box {
width: 50px;
height: 35px;
background: #2563eb;
margin-block: 0.5rem;
}
label {
display: inline-block;
padding: 0.75rem;
}
.run:checked ~ .stage .box {
animation: travel 1s linear 0s 2 alternate forwards;
}
@media (prefers-reduced-motion: reduce) {
.run:checked ~ .stage .box {
animation-name: none;
}
}
Edit HTML or CSS to update the preview as you type. Copy code snippet copies the selected tab. Preview spacing and font defaults are not included.
Values and defaults
The initial value is normal and the property is not inherited. Normal restarts forward each iteration; reverse restarts backward. Alternate begins forward and switches direction each iteration; alternate-reverse begins backward and switches. Reversed playback also reverses the easing, so ease-in behaves as ease-out in the reversed traversal.
Common mistakes
Direction does not change the DOM order or layout direction. Alternate with one iteration has no return trip. Forwards fill retains the last keyframe encountered, which depends on direction and iteration count, rather than always retaining 100%. Comma-separated directions match animation-name order. A later shorthand resets this setting.
Learn animation-iteration-count, animation-fill-mode, and animation-timing-function.
The demonstrations are stationary when prefers-reduced-motion:reduce is active. Their code remains available for inspection.
Sources and browser support
MDN: animation-direction describes the syntax and links to the specification and compatibility data. Check individual values in that table when supporting older browsers.