Skip to content
TaeyoungKim.dev

Why a CSS animation snaps back: animation-fill-mode forwards

WebWritten 3 min readTaeyoungKim
LinkedInX

A notification badge slides to the right, then returns to its starting point one second later. Before changing @keyframes, check which style applies after the animation finishes. CSS played the movement; it did not save the final position as the badge's base style.

Why does the element return to its original position?

@keyframes defines property values during the animation. In this example, the badge's base transform is translateX(0), and the animation moves it 120px to the right over one second. With the default animation-fill-mode: none, the base position applies again after playback.

Both rows in the diagram start at the same place and move the same distance. Only the post-animation behavior differs. forwards retains the value from the end of the animation. The relevant property is animation-fill-mode: forwards, not animation-direction: forwards.

Apply animation-fill-mode: forwards

Save this HTML as a file and open it. Both badges move; after one second, the first returns and the second remains on the right.

html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Compare animation-fill-mode</title>
  <style>
    .track { width: 240px; height: 48px; margin: 12px 0; border-bottom: 1px solid #93c5fd; }
    .chip {
      width: 96px;
      padding: 6px 0;
      text-align: center;
      background: #dbeafe;
      transform: translateX(0);
      animation: move 1s linear 1;
    }
    .keep { animation-fill-mode: forwards; }
    @keyframes move {
      from { transform: translateX(0); }
      to   { transform: translateX(120px); }
    }
  </style>
</head>
<body>
  <div class="track"><div class="chip">none</div></div>
  <div class="track"><div class="chip keep">forwards</div></div>
</body>
</html>

The first badge omits animation-fill-mode, so it uses none. Only .keep uses forwards. If neither moves, confirm that @keyframes move matches animation: move ... and that the duration is not missing or 0s. That is a different problem from snapping back after movement.

Does forwards permanently save the final position?

No. forwards displays the final value while the animation still applies to the element. Remove the class that applies the animation and the base style returns. The CSS Animations specification distinguishes the default none from forwards, which applies the value reached when the animation ends.

If the badge has genuinely entered a completed UI state that must persist, do not treat the animation as state storage. Apply a state class with the final position, then remove the animation class as appropriate. For a temporary visual effect, forwards alone may be enough.

forwards does not always mean the to keyframe. With reverse or alternate iteration directions, the final completed iteration can end on a different side. This example runs once in the normal direction, so the 120px to value remains.

Key takeaways

An animation often snaps back because animation-fill-mode defaults to none. For the same movement, forwards retains the final animated value, but it is not permanent UI state. If nothing moves at all, check the animation name and duration; if a completed state must persist, represent it separately in the element's styles.

Author

TaeyoungKim

Connecting technical foundations with implementation, verification, and production decisions.

#CSS animation#animation-fill-mode#keyframes

Read next