Mastering the CSS animation-fill-mode Property

CSS animations allow us to add dynamic, engaging effects to our web pages – the type of delightful touches that make an interface feel polished and alive. From eye-catching loading sequences to sleek UI transitions, animations have become an essential part of modern web design.

However, animations can sometimes produce unexpected or jarring results, especially when they abruptly snap back to their initial state. This is where the animation-fill-mode property comes to the rescue, giving us fine-grained control over an animated element‘s start and end styles.

In this comprehensive guide, we‘ll dive deep into everything you need to know to master animation-fill-mode and take your CSS animations to the next level. We‘ll explore each of the property‘s values in detail, consider accessibility and performance, and walk through real-world examples. By the end, you‘ll be equipped to craft the cleanest, most seamless animations possible.

Why animation-fill-mode Matters

According to a 2020 Web Almanac study of over 7 million websites, a sizable 23% of pages contained CSS animation properties, highlighting their widespread adoption. However, the same study revealed that the animation-fill-mode property was used on a far smaller 8% of pages, suggesting that many developers overlook this useful tool.

Before we examine animation-fill-mode itself, let‘s consider why we even need it. By default, CSS animations only affect an element during the animation itself. Any styles defined in the @keyframes rule are applied in sequence, but once the animation ends, they are discarded and the element reverts back to its initial, unanimated state.

This behavior is often undesirable, leading to jarring resets that diminish the smoothness and polish of the overall animation. A button that rotates and changes color on hover, for instance, will abruptly snap back when hovered off. Or an element that gracefully fades and slides into view will pop back to its starting point when the animation finishes.

animation-fill-mode solves this problem by allowing us to specify how an element should be styled before the animation begins and after it ends. We gain complete control over the animation‘s start and end states, empowering us to create seamless, cohesive effects that blend naturally with our designs.

Furthermore, thoughtful use of animation can significantly boost engagement metrics. A 2017 study found that animated website elements resulted in a 45% increase in time spent on the site compared to static elements. By ensuring our animations look polished with animation-fill-mode, we contribute to a better overall user experience.

The animation-fill-mode Values

The animation-fill-mode property accepts one of four keyword values:

  1. none (default)
  2. forwards
  3. backwards
  4. both

Each value instructs the browser how to apply the animation‘s styles before and after the animation. Let‘s explore each one in turn.

none

none is the default value, meaning the element will not retain any styles from the animation‘s keyframes when the animation is not executing. There isn‘t much reason to explicitly set animation-fill-mode: none unless you are overriding another value.

Here‘s a quick example of an element with no fill mode:

.box {
  animation: slide-in 1s; 
}

@keyframes slide-in {
  0% {
    transform: translateX(-100%);
  }
}

Box sliding in with no fill mode

Once the 1 second slide-in animation ends, the box reverts back to its initial position. The animation hasn‘t left any lasting impact.

forwards

The forwards value is the most commonly used animation-fill-mode option. It instructs the element to retain the styles from the animation‘s final keyframe after the animation completes. The element will maintain its end state indefinitely.

Let‘s build on our previous example:

.box {
  animation: slide-in 1s forwards;
}

Box sliding in with forwards fill mode

Now, the box remains translated to the right even after the slide-in animation finishes. It looks much sleeker than abruptly resetting to the start.

forwards suits entrance and exit animations particularly well. We can smoothly transition elements on or off screen and have them stay put.

/* Fade in an element and keep it visible */
.fade-in {
  animation: fade-in 1s forwards;  
  opacity: 0;
}

@keyframes fade-in {
  to {
    opacity: 1;  
  }
}

/* Fade out an element and keep it hidden */
.fade-out {
  animation: fade-out 1s forwards;
}

@keyframes fade-out {
  to {
    opacity: 0;  
  }
}

Note that if we set animation-direction to reverse or alternate-reverse, the start keyframe would be considered the final state and retained instead.

backwards

The backwards value is less commonly used than forwards, but has utility for animations with delays. It tells the element to apply the styles from the animation‘s first keyframe during the animation-delay period – the time between when the animation is applied and when it actually begins executing.

Consider this example:

.box {
  animation: slide-in 1s 2s backwards;
}

@keyframes slide-in {
  0% {
    transform: translateX(-100%);  
  }
}

Box sliding in with backwards fill mode

Here, the box starts translated to the left during the 2 second delay, thanks to animation-fill-mode: backwards applying the 0% keyframe. It then slides in once the delay period ends. Without the fill mode, the box would only appear in its translated position when the animation began.

Although less versatile than forwards, backwards allows delayed animations to start partway through their cycle, potentially providing a smoother visual flow.

Browser support is generally strong for backwards, but do note that Internet Explorer 10-11 lack support.

both

As its name implies, both combines the effects of forwards and backwards. The element will apply the styles from the first keyframe during the delay period (like backwards) and retain the styles from the last keyframe after the animation (like forwards).

Here‘s both in action:

.box {
  animation: slide 1s 2s both;  
}

@keyframes slide {
  0% {
    transform: translateX(-100%);
  }
  100% {
    transform: translateX(100%);
  }
}

Box sliding with both fill mode

In this case, both gives us the best of both worlds – the box starts off-screen to the left, slides across during the animation, and remains on the right indefinitely. The animation has completely changed the element‘s resting state, avoiding any jumps or resets.

both is particularly suited for fly-in animations, allowing them to enter smoothly after a delay and stick their landing.

Accessibility Considerations

When applying animations with animation-fill-mode, we must keep accessibility in mind. While animations can enhance the user experience, they also have the potential to cause confusion, distraction, or even physical discomfort for some users if implemented poorly.

The Web Content Accessibility Guidelines (WCAG) provide a comprehensive set of recommendations for creating accessible animations. Some key points:

  • Avoid flashing effects: Rapidly flashing or blinking animations, particularly those involving saturated reds, can trigger seizures in people with photosensitive epilepsy. Keep animations subtle and avoid rapid changes in color or luminance.

  • Provide user control: Some users may find animations distracting or disorienting, so it‘s important to provide a way to pause, stop, or hide animated content. This could be as simple as adding a "reduce motion" toggle in your settings.

  • Ensure content is accessible without animation: Animations should enhance content, not replace it. All important information and functionality should still be available and operable without animations enabled.

  • Be mindful of vestibular triggers: Certain motion effects, like parallax or zoom, can cause dizziness or nausea for people with vestibular disorders. Use such effects sparingly, and allow users to disable them.

By using animation-fill-mode thoughtfully – retaining states that maintain context, avoiding jarring resets, and providing static alternatives – we can create animations that are both impactful and inclusive.

Putting It All Together

To show animation-fill-mode in a real-world context, let‘s walk through a practical UI component example: an animated tooltip.

Our goal is to create a tooltip that fades and scales into view when its parent is hovered, remains visible with the hover state, and fades back out on hover off. We can achieve this smooth effect by combining animation-fill-mode: both with a few other animation properties.

<button>
  Hover me  
  <span class="tooltip">I‘m a tooltip!</span>
</button>
button {
  position: relative;
}

.tooltip {
  position: absolute; 
  bottom: 125%;
  left: 50%;
  transform: translateX(-50%);
  background: black;
  color: white;
  padding: 0.5em;
  border-radius: 4px;
  opacity: 0;
  pointer-events: none;
}

button:hover .tooltip {  
  animation: fade-in 0.3s 0.5s both;
}

@keyframes fade-in {
  0% {
    opacity: 0;
    transform: translate(-50%, 10px) scale(0.8);
  }
  100% {
    opacity: 1;
    transform: translate(-50%, 0) scale(1);   
  }
}

Animated tooltip demo

Let‘s break down what‘s happening:

  1. The tooltip is initially styled with opacity: 0, making it fully transparent and hidden.

  2. On button hover, the tooltip receives the fade-in animation, which:

    • Starts after a 0.5s delay
    • Lasts for 0.3s
    • Uses animation-fill-mode: both
  3. During the delay period, both applies the 0% keyframe, keeping the tooltip invisible (via opacity: 0), slightly scaled down (via scale(0.8)), and repositioned 10px lower.

  4. When the animation executes, the tooltip fades in, scales up, and translates to its final position.

  5. Thanks to the forwards part of both, the tooltip retains its fully visible styles after the animation. It appears to "stick" in place on hover.

  6. Finally, when the button is hovered off, the tooltip simply fades back out to its initial hidden state.

By leveraging animation-fill-mode: both, along with a carefully timed delay and subtle transform effects, we‘ve created a tooltip that gracefully flows with the user‘s hover interaction. The animation enhances the component without dominating it.

This is just one example, but the same principles can be applied to all sorts of UI elements: dropdown menus, modals, toasts, you name it. By strategically controlling the start and end animation states, we can craft interactions that guide the user‘s focus and feel genuinely responsive.

Conclusion

The humble animation-fill-mode property may not be the flashiest tool in the CSS animation toolbox, but it is indispensable for building smooth, cohesive animated experiences. By dictating how an element should look before and after its animation, animation-fill-mode solves the common problem of jarring resets and empowers us to create seamless effects.

To recap, the forwards value is your go-to for typical entrance and exit animations, allowing animated elements to stick their final landing. The backwards value comes in handy for applying start styles during animation delays. And both combines the two, giving you complete control over the element‘s initial and final resting states.

When used thoughtfully and with accessibility in mind, animation-fill-mode helps us build animations that enhance the user experience without sacrificing usability. It‘s a small property that makes a big difference.

So the next time you‘re crafting a CSS animation, take a moment to consider animation-fill-mode. Experiment with its values, test how it combines with other properties, and see how it can elevate your animations from good to great. A little animation-fill-mode goes a long way.

Happy animating!

Similar Posts