animation-direction
Setting the direction of the animation.
Overview
| Class | Declarations |
|---|---|
animation-direction:normal | animation-direction: normal;
|
animation-direction:reverse | animation-direction: reverse;
|
animation-direction:alternate | animation-direction: alternate;
|
animation-direction:alternate-reverse | animation-direction: alternate-reverse;
|
animation-direction:<value>,<…> | animation-direction: <value>,<…>;
|
Basic usage
Play forward
Play each cycle from 24px to 96px. The one-second linear path repeats with the same direction.
@theme { @keyframes layer-slide { from { transform: translateX(24px); } to { transform: translateX(96px); } }}<!-- normal --><div class="w:240px max-w:100%"> <p class="mb-sm font-mono font-xs text-muted">Base 0 · start 24 · end 96px</p> <div aria-hidden="true" class="h:56px p-xs outline:1px|dashed|var(--color-line-muted)"> <span id="target" class="grid place-items:center h:40px w:48px b:1px|solid|var(--color-blue-60) r-sm bg-blue-10 fg-blue-80 transform:none animation-direction:normal animation-duration:1s animation-iteration-count:infinite animation-name:layer-slide animation-timing-function:linear animation:none@print animation-play-state:paused@reduce-motion">→</span> </div></div>Generated CSS
@layer utilities { .animation-direction\:normal { animation-direction: normal }}A new normal cycle jumps back to its starting keyframe. Direction does not change the number or duration of cycles.
Play backward
Play each cycle from 96px back to 24px by reversing the same keyframes.
@theme { @keyframes layer-slide { from { transform: translateX(24px); } to { transform: translateX(96px); } }}<!-- reverse --><div class="w:240px max-w:100%"> <p class="mb-sm font-mono font-xs text-muted">Base 0 · start 24 · end 96px</p> <div aria-hidden="true" class="h:56px p-xs outline:1px|dashed|var(--color-line-muted)"> <span id="target" class="grid place-items:center h:40px w:48px b:1px|solid|var(--color-blue-60) r-sm bg-blue-10 fg-blue-80 transform:none animation-direction:reverse animation-duration:1s animation-iteration-count:infinite animation-name:layer-slide animation-timing-function:linear animation:none@print animation-play-state:paused@reduce-motion">→</span> </div></div>Reverse also reverses easing. An ease-in curve read backward behaves like ease-out; this linear example keeps speed constant.
Play alternately
Play the first cycle forward, then the second backward. The direction changes at each one-second boundary.
@theme { @keyframes layer-slide { from { transform: translateX(24px); } to { transform: translateX(96px); } }}<!-- alternate --><div class="w:240px max-w:100%"> <p class="mb-sm font-mono font-xs text-muted">Base 0 · start 24 · end 96px</p> <div aria-hidden="true" class="h:56px p-xs outline:1px|dashed|var(--color-line-muted)"> <span id="target" class="grid place-items:center h:40px w:48px b:1px|solid|var(--color-blue-60) r-sm bg-blue-10 fg-blue-80 transform:none animation-direction:alternate animation-duration:1s animation-iteration-count:infinite animation-name:layer-slide animation-timing-function:linear animation:none@print animation-play-state:paused@reduce-motion">→</span> </div></div>Iterations are counted from one. Odd iterations go forward and even iterations go backward, so the marker returns without a jump between these endpoints.
Play alternately and reverse first
Start at 96px and play backward first, then forward on the next cycle.
@theme { @keyframes layer-slide { from { transform: translateX(24px); } to { transform: translateX(96px); } }}<!-- alternate-reverse --><div class="w:240px max-w:100%"> <p class="mb-sm font-mono font-xs text-muted">Base 0 · start 24 · end 96px</p> <div aria-hidden="true" class="h:56px p-xs outline:1px|dashed|var(--color-line-muted)"> <span id="target" class="grid place-items:center h:40px w:48px b:1px|solid|var(--color-blue-60) r-sm bg-blue-10 fg-blue-80 transform:none animation-direction:alternate-reverse animation-duration:1s animation-iteration-count:infinite animation-name:layer-slide animation-timing-function:linear animation:none@print animation-play-state:paused@reduce-motion">→</span> </div></div>Odd iterations run backward and even iterations run forward. The keyframes, duration and easing remain identical to the alternate example.
Fade out
Reverse the preset fade keyframes, which normally go from opacity 0 to 1. This one-shot example fades its decorative marker out over one second.
<!-- Fades out once --><div class="flex items-center gap-md p-sm"> <span id="target" aria-hidden="true" class="block h:40px w:64px b:1px|solid|var(--color-blue-60) r-sm bg-blue-10 opacity:1 animation-direction:reverse animation-duration:1s animation-fill-mode:forwards animation-name:fade animation-timing-function:linear animation:none@print animation-play-state:paused@reduce-motion"></span> <span class="font-sm">Fades out once</span></div>Forwards fill retains the last value of the completed reverse iteration: opacity 0. The visible message remains readable, and print removes the animation.
Apply conditionally
Resize before replaying. The path runs backward below sm and forward at sm, using a real viewport query.
@theme { @keyframes layer-slide { from { transform: translateX(24px); } to { transform: translateX(96px); } }}<!-- Reverse → normal at sm --><div class="w:240px max-w:100%"> <p class="mb-sm font-mono font-xs text-muted">Base 0 · start 24 · end 96px</p> <div aria-hidden="true" class="h:56px p-xs outline:1px|dashed|var(--color-line-muted)"> <span id="target" class="grid place-items:center h:40px w:48px b:1px|solid|var(--color-blue-60) r-sm bg-blue-10 fg-blue-80 transform:none animation-direction:reverse animation-duration:1s animation-iteration-count:infinite animation-name:layer-slide animation-timing-function:linear animation:none@print animation-play-state:paused@reduce-motion animation-direction:normal@sm">→</span> </div></div>Direction changes reuse the existing timeline; they do not inherently restart it. Replay starts the comparison again from time zero.