Note: This article is written in standard American English for web publishing and focuses on practical, real-world use of the CSS animation-fill-mode property.
CSS animations are a little like stage actors. They enter, perform their dramatic spin, fade, bounce, or slide, and thenunless you tell them otherwisethey walk offstage and pretend nothing ever happened. That is charming in theater, but slightly annoying in interface design. Imagine a button smoothly sliding into place, only to jump back to where it started like it remembered it left the oven on. That awkward reset is exactly where the animation-fill-mode property earns its paycheck.
The animation-fill-mode property controls how styles from a CSS animation apply before the animation begins and after it ends. In simple terms, it answers one question: should the element keep the style from its keyframes when the animation is not actively running?
If you have ever built a loading screen, animated hero section, notification badge, modal entrance, product card reveal, or call-to-action button that needed to stay put after moving, this property is not optional trivia. It is the difference between a polished interface and a website that looks like it tripped over its own shoelaces.
What Is CSS animation-fill-mode?
The CSS animation-fill-mode property defines what happens to an animated element outside the active animation period. That “outside” period can mean two things: the time before the animation starts, especially when animation-delay is used, and the time after the animation finishes.
By default, CSS animations do not permanently apply the styles inside @keyframes. The browser uses those keyframe styles only while the animation is running. When the animation ends, the element returns to the styles it had before the animation took control. That default behavior is logical, but it often surprises developers who expect the final keyframe to stick around.
Here is the basic syntax:
You can also use it inside the animation shorthand:
The property has four commonly used values: none, forwards, backwards, and both. Each one controls whether the element borrows styles from the first or last keyframe before or after the animation runs.
Why animation-fill-mode Matters
Without animation-fill-mode, CSS animations can create visual jumps. The animation may begin from one state, finish in another, and then suddenly snap back to the original CSS declaration. That might be fine for a pulsing icon or a looping spinner, but it is usually terrible for entrance animations and state-based UI effects.
For example, suppose a card fades in from opacity: 0 to opacity: 1. If the element’s normal style does not include opacity: 1, the card may appear during the animation and then return to its earlier state. The user sees a flash instead of a clean reveal. Not exactly the “premium digital experience” anyone was hoping for.
This property is especially useful when you want to:
- Keep an element in its final animated position.
- Apply the first keyframe during an animation delay.
- Prevent flickering before an animation starts.
- Create smooth entrance animations.
- Control the visual state of modals, tooltips, alerts, and banners.
- Make CSS keyframe animations feel intentional instead of jumpy.
The Four animation-fill-mode Values
1. animation-fill-mode: none
none is the default value. It means the animation does not apply any keyframe styles before it starts or after it ends. The element uses its regular CSS styles outside the active animation window.
In this example, the element moves to the right during the animation. Once the animation ends, it returns to its original position. This is useful for temporary motion, such as a shake effect on an invalid form field. The field shakes, then returns to normal. Nobody wants a permanently trembling email input. That would be concerning.
2. animation-fill-mode: forwards
forwards tells the browser to keep the styles from the final keyframe after the animation finishes. This is one of the most common values because many animations are designed to move an element into a new final state.
Now the element moves 200 pixels to the right and stays there. No dramatic return. No awkward snap. No tiny CSS betrayal.
Use forwards when you want the final frame to become the visible ending state. It works well for fade-ins, slide-ins, progress indicators, menu reveals, and success messages.
3. animation-fill-mode: backwards
backwards applies the styles from the first relevant keyframe before the animation starts. This is most noticeable when the animation has a delay.
Here, the animation waits two seconds before running. Because animation-fill-mode is set to backwards, the element immediately uses the first keyframe during that waiting period. It starts hidden and slightly lower, then animates into view when the delay ends.
Without backwards, the element might be visible during the delay and then suddenly jump to the first keyframe when the animation begins. That creates the classic “why did my layout blink at me?” problem.
4. animation-fill-mode: both
both combines forwards and backwards. The element uses the first keyframe before the animation begins and keeps the final keyframe after it ends.
This is often the safest choice for delayed entrance animations. The element starts in the intended hidden state, waits politely during the delay, animates in, and remains visible afterward. It is the CSS equivalent of arriving on time and not leaving through a window.
How animation-fill-mode Works with @keyframes
The @keyframes rule defines the states of an animation. The browser interpolates between those states during the animation duration. The animation-fill-mode property decides whether the beginning or ending keyframe styles should apply outside that duration.
Consider this animation:
During the animation, the badge changes from gray to gold and grows slightly. With forwards, the badge remains gold and enlarged after the animation ends. Without it, the badge returns to its original gray style.
This matters because the keyframe declaration is not the same as the element’s permanent CSS. Keyframes are temporary instructions. Fill mode decides whether those temporary instructions leave a visual footprint.
animation-fill-mode and animation-direction
One detail that often confuses developers is how animation-fill-mode behaves when animation-direction changes. The “first” and “last” keyframes can depend on the direction of the animation.
For example, if an animation runs in reverse, the ending state may come from the from or 0% keyframe rather than the to or 100% keyframe. With alternate or alternate-reverse, the final visual state can also depend on the number of animation iterations.
Because the animation runs in reverse, the element begins from the to state and finishes at the from state. With forwards, it keeps the final state based on that reversed playback. This is why animation direction should always be considered when debugging fill mode behavior.
animation-fill-mode with Multiple Animations
CSS allows multiple animations on one element. In that case, animation-fill-mode can accept multiple comma-separated values, matching the order of the animation names.
In this example, fadeIn uses forwards, while liftUp uses both. This level of control is helpful when combining opacity, transform, color, or layout-related effects. However, keep the list readable. If your animation declaration starts looking like a grocery receipt from a very nervous designer, it may be time to simplify.
Practical Example: A Smooth Hero Text Reveal
Here is a common real-world use case: revealing hero section text after the page loads.
This works because the normal style starts with the title hidden and shifted downward. The animation moves it into place, and forwards keeps it visible at the end. This pattern is clean, predictable, and easy to maintain.
Another option is to put the hidden state inside the first keyframe and use both:
This version prevents the title from flashing before the delayed animation starts. For delayed entrance effects, both is often the more reliable choice.
Common Mistakes with animation-fill-mode
Expecting forwards to Change the Actual CSS Rule
animation-fill-mode: forwards keeps the final animated style visually applied, but it does not rewrite your stylesheet. The original CSS rule still exists. This can matter when JavaScript, hover states, media queries, or future animations try to change the same property.
If an element must permanently change state after an interaction, sometimes adding a class is clearer than relying only on fill mode.
Use animation fill mode for visual continuity. Use state classes for long-term interface logic.
Using forwards Everywhere
forwards is useful, but it is not seasoning salt. Sprinkling it on every animation can make styles harder to reason about. If an animation is decorative, temporary, or repeating forever, forwards may do nothing useful.
For looping animations such as spinners, pulsing buttons, floating icons, or skeleton loaders, fill mode usually matters less because the animation does not truly end while it is active.
Forgetting About animation-delay
If your animation has a delay and the element appears in the wrong style before the animation starts, backwards or both may be the missing piece. Delays are where fill mode becomes very visible.
Animating Layout Properties Too Often
Fill mode controls animation states, but it does not magically make every CSS property cheap to animate. For smoother performance, prioritize transform and opacity for motion effects. Animating properties that trigger layout recalculation, such as width, height, top, or left, can be more expensive, especially on complex pages.
Best Practices for Using animation-fill-mode
Use forwards for Final-State Animations
If the purpose of the animation is to move the element into a new final state, use forwards. This works well for reveal animations, completion states, onboarding steps, and animated UI feedback.
Use backwards for Delayed Starts
If the element should look like the first keyframe during a delay, use backwards. This avoids flashes and sudden jumps before the animation begins.
Use both for Entrance Animations with Delays
For most delayed entrance animations, both is a strong choice. It applies the starting keyframe before the animation and preserves the ending keyframe afterward.
Keep Keyframes Focused
Do not put too many unrelated property changes into a single animation. A fade-and-slide animation is easy to understand. A fade-slide-rotate-color-shadow-width extravaganza may technically work, but future you may open the file and whisper, “Who hurt us?”
Respect Reduced Motion Preferences
Animations can improve user experience, but not everyone wants motion. Some users experience discomfort from movement-heavy interfaces. Use the prefers-reduced-motion media query to reduce or remove nonessential animation.
This keeps the content accessible while preserving the design intent.
Quick Comparison Table
| Value | Before Animation | After Animation | Best Use Case |
|---|---|---|---|
none |
Uses normal CSS | Returns to normal CSS | Temporary effects |
forwards |
Uses normal CSS | Keeps final keyframe | Final-state animations |
backwards |
Uses first keyframe | Returns to normal CSS | Animations with delay |
both |
Uses first keyframe | Keeps final keyframe | Delayed entrance animations |
Real-World Experience: Lessons from Using animation-fill-mode
In real projects, animation-fill-mode tends to show up when something “almost works.” The animation is smooth, the timing feels good, the keyframes are correct, and then the element snaps back at the end like a rubber band. That moment is usually when developers discover forwards. It feels like finding the missing screw after assembling an entire desk.
One of the most common experiences is building a landing page with staggered content. The headline appears first, then the paragraph, then the button. Each element has a small delay. Without backwards or both, the delayed elements can briefly appear in their normal state before the animation begins. This creates a flicker that is hard to ignore once you notice it. Using animation-fill-mode: both usually solves the problem because each element adopts its first keyframe immediately, waits during the delay, animates, and then holds its final state.
Another practical lesson is that forwards should not replace good state management. For example, if a menu opens after a button click, an animation can make the opening feel smooth. But the menu’s open or closed state should usually be represented by a class such as .is-open. The animation can enhance the transition, while the class defines the actual interface state. Relying only on forwards can become confusing when the same element later needs to close, respond to a media query, or animate again.
There is also a debugging lesson: always check which property is responsible for the final visual result. If an element refuses to change after an animation, the filled animation may still be applying styles. This is especially relevant when using browser DevTools. Inspect the element, look at the active animations, and check whether the final keyframe is still influencing properties such as transform, opacity, or background-color. The issue may not be specificity in the usual CSS sense. It may be the animation effect still holding the visual state.
From a design perspective, animation-fill-mode is most valuable when it supports continuity. Users should feel that an element moved somewhere for a reason. A toast notification sliding in and staying visible makes sense. A success checkmark scaling up and remaining visible makes sense. A card entering the viewport and then jumping back down does not make sense, unless the card is haunted, and haunted UI is rarely in the brand guidelines.
The best workflow is to decide the element’s before, during, and after states before writing the animation. Ask three simple questions: What should the user see before the animation starts? What should change during the animation? What should remain after it ends? If the first keyframe should apply before the animation, use backwards. If the last keyframe should remain afterward, use forwards. If both are true, use both. If neither is true, stay with none.
In production, the cleanest animations are usually the least dramatic. A subtle fade, a short vertical movement, and a sensible fill mode can make a page feel modern without turning it into a carnival ride. Pair animation-fill-mode with short durations, natural easing, and accessibility fallbacks, and you will avoid most of the classic CSS animation headaches.
Conclusion
The animation-fill-mode property may not sound glamorous, but it plays a major role in making CSS animations feel polished. It controls whether keyframe styles apply before an animation starts, after it ends, or both. Use none for temporary effects, forwards to keep the final state, backwards to apply the first keyframe during delays, and both when you need complete before-and-after control.
When used thoughtfully, animation-fill-mode prevents flickers, jumps, and unexpected resets. It helps animated elements behave like they belong in the interface instead of randomly teleporting around the page. Combine it with clean keyframes, performance-friendly properties, and reduced-motion support, and your CSS animations will look smoother, feel more intentional, and cause far fewer “why is it doing that?” moments.
