The animation-fill-mode property is one of the most powerful yet underutilized features in CSS animations. It determines how an element should be styled before the animation starts and after it ends, giving you complete control over the visual state transitions of your animated elements.
What is CSS Animation-Fill-Mode?
The animation-fill-mode property specifies how CSS animations apply styles to their target elements before and after they execute. By default, animations don’t affect an element’s appearance outside their active duration, but this property changes that behavior.
Syntax
animation-fill-mode: none | forwards | backwards | both;
Understanding the Four Values
1. none (Default Value)
The none value is the default behavior where the animation doesn’t apply any styles to the element when it’s not executing. The element returns to its original state after the animation completes.
Example: none Value
.element {
animation: moveRight 2s ease-in-out;
animation-fill-mode: none;
}
@keyframes moveRight {
0% { transform: translateX(0); background: #007bff; }
100% { transform: translateX(200px); background: #28a745; }
}
2. forwards
The forwards value makes the element retain the styles from the last keyframe after the animation completes. This is particularly useful when you want permanent changes to persist.
Example: forwards Value
.element {
animation: moveRight 2s ease-in-out;
animation-fill-mode: forwards;
}
@keyframes moveRight {
0% { transform: translateX(0); background: #007bff; }
100% { transform: translateX(200px); background: #28a745; }
}
3. backwards
The backwards value applies the styles from the first keyframe to the element during the animation delay period (if any) and before the animation starts.
Example: backwards Value
.element {
animation: moveRight 2s ease-in-out 1s; /* 1s delay */
animation-fill-mode: backwards;
}
@keyframes moveRight {
0% { transform: translateX(0); background: #dc3545; }
100% { transform: translateX(200px); background: #28a745; }
}
4. both
The both value combines the effects of both forwards and backwards, applying first keyframe styles before the animation and retaining last keyframe styles after completion.
Example: both Value
.element {
animation: moveRight 2s ease-in-out 1s; /* 1s delay */
animation-fill-mode: both;
}
@keyframes moveRight {
0% { transform: translateX(0); background: #dc3545; }
100% { transform: translateX(200px); background: #28a745; }
}
Interactive Demo: Compare All Values
Animation Fill Mode Comparison
none
forwards
backwards
both
Practical Use Cases
1. Loading Spinners with Persistent End State
When creating loading animations, you often want the spinner to remain in its final state once loading completes:
.loading-spinner {
animation: spin 1s linear infinite;
animation-fill-mode: forwards;
}
.loading-spinner.complete {
animation: fadeOut 0.5s ease-out;
animation-fill-mode: forwards;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
@keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
2. Hover Effects with Smooth Transitions
Use animation-fill-mode to create smooth hover effects that maintain their end state:
.button {
transition: all 0.3s ease;
animation-fill-mode: forwards;
}
.button:hover {
animation: buttonHover 0.3s ease-out;
animation-fill-mode: forwards;
}
@keyframes buttonHover {
from {
transform: scale(1);
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
to {
transform: scale(1.05);
box-shadow: 0 8px 16px rgba(0,0,0,0.2);
}
}
3. Sequential Animations
When chaining multiple animations, animation-fill-mode ensures smooth transitions between states:
.sequence-item {
animation:
slideIn 0.5s ease-out,
pulse 1s ease-in-out 0.5s,
slideOut 0.5s ease-in 1.5s;
animation-fill-mode: both;
}
@keyframes slideIn {
from { transform: translateX(-100%); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.1); }
}
@keyframes slideOut {
from { transform: translateX(0); opacity: 1; }
to { transform: translateX(100%); opacity: 0; }
}
Common Pitfalls and Solutions
1. Conflicting CSS Properties
When using animation-fill-mode: forwards, ensure that conflicting CSS properties don’t override your animation’s end state:
/* ❌ Problematic */
.element {
transform: translateX(0); /* This will override the animation */
animation: moveRight 2s forwards;
}
/* ✅ Correct */
.element {
animation: moveRight 2s forwards;
/* Remove conflicting transform property */
}
2. Animation Delay Considerations
Remember that backwards and both only affect elements during the delay period:
/* With delay - backwards has effect */
.element-with-delay {
animation: slideIn 1s ease-out 0.5s backwards;
}
/* Without delay - backwards has no effect */
.element-no-delay {
animation: slideIn 1s ease-out backwards;
}
Browser Support and Performance
The animation-fill-mode property enjoys excellent browser support across all modern browsers. It’s been supported since:
- Chrome 43+
- Firefox 16+
- Safari 9+
- Edge 12+
- Internet Explorer 10+
Performance Considerations
Using animation-fill-mode doesn’t significantly impact performance, but consider these tips:
- Use
transformandopacityproperties for better performance - Avoid animating layout-triggering properties like
widthorheight - Consider using
will-changeproperty for complex animations
Advanced Techniques
1. Combining with CSS Variables
Create dynamic animations by combining animation-fill-mode with CSS custom properties:
.dynamic-element {
--end-position: 200px;
--end-color: #28a745;
animation: dynamicMove 2s ease-out forwards;
animation-fill-mode: forwards;
}
@keyframes dynamicMove {
from {
transform: translateX(0);
background: #007bff;
}
to {
transform: translateX(var(--end-position));
background: var(--end-color);
}
}
2. Responsive Animation States
Use media queries to control animation fill modes based on screen size:
.responsive-animation {
animation: mobileSlide 1s ease-out;
animation-fill-mode: forwards;
}
@media (min-width: 768px) {
.responsive-animation {
animation: desktopSlide 1s ease-out;
animation-fill-mode: both;
}
}
@keyframes mobileSlide {
from { transform: translateY(-20px); }
to { transform: translateY(0); }
}
@keyframes desktopSlide {
from { transform: translateX(-50px); }
to { transform: translateX(0); }
}
Testing and Debugging
When working with animation-fill-mode, use browser developer tools to:
- Inspect the computed styles during different animation phases
- Use the animation panel to control playback speed
- Check for conflicting CSS properties
- Verify that the expected styles are applied before and after animations
Conclusion
The animation-fill-mode property is essential for creating polished, professional animations in CSS. By understanding how none, forwards, backwards, and both work, you can control exactly how your elements behave before, during, and after animations.
Remember to consider the specific needs of your animation: use forwards when you want changes to persist, backwards for pre-animation styling during delays, and both when you need complete control over the entire animation lifecycle. With these techniques, you’ll create more engaging and visually appealing web experiences.








