animation-direction
| Value | Plays |
|---|---|
normal | From start to end every time (default) |
reverse | From end to start |
alternate | Forward, then backward, then forward… |
alternate-reverse | Backward first, then forward… |
<style>
@keyframes slide { from { transform: translateX(0); } to { transform: translateX(220px); } }
.track { background: #eee; margin: 6px 0; font-size: 12px; }
.dot { width: 26px; height: 26px; border-radius: 50%; background: #1a5276; animation: slide 2s linear infinite; }
.a { animation-direction: normal; }
.b { animation-direction: reverse; background: #d94a00; }
.c { animation-direction: alternate; background: #27ae60; }
</style>
<div class="track">normal<div class="dot a"></div></div>
<div class="track">reverse<div class="dot b"></div></div>
<div class="track">alternate<div class="dot c"></div></div>
alternate gives a smooth back-and-forth with no jump.
animation-fill-mode
What the element looks like before the animation starts and after it ends.
| Value | Meaning |
|---|---|
none | The animation has no effect outside its running time (default) |
forwards | Keep the last keyframe’s styles after it ends |
backwards | Apply the first keyframe during a delay |
both | Both of the above |
<style>
@keyframes appear { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }
.a, .b { padding: 12px; margin: 6px 0; background: #fdebd9; border-left: 4px solid #d94a00; animation: appear 0.8s 1s; }
.b { animation-fill-mode: both; }
</style>
<div class="a">Without fill-mode: visible during the 1s delay, then flashes</div>
<div class="b">fill-mode: both: hidden during the delay, then fades in and stays</div>
Press Run and watch both. The first box is fully visible during the delay, then disappears and animates in. That flash is why both or backwards is the right choice for delayed entry animations.
The two to remember
alternate for loops that go back and forth, and both (or forwards) for one-time entrance animations that should stay in place.