CSS Animations and Keyframes: A Complete Guide for Developers
CSS animations bring interfaces to life. From subtle hover effects to complex multi-step transitions, the animation property and @keyframes rule give you fine-grained control over how elements move, fade and transform. This guide covers everything you need to build performant, accessible animations with pure CSS.
The @keyframes Rule
A keyframe block defines what an animation looks like at specific points during its timeline. You specify percentages (or from / to as aliases for 0% and 100%) and the browser interpolates the values between them.
from { opacity: 0; }
to { opacity: 1; }
}
For multi-step animations, use percentage keyframes to define intermediate states.
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-20px); }
}
The Animation Property
The animation shorthand combines several sub-properties into a single declaration.
iteration-count direction fill-mode;
Here is a practical example that fades in an element over 400 milliseconds.
animation: fadeIn 400ms ease-out forwards;
}
Each sub-property can also be set individually: animation-name, animation-duration, animation-timing-function, animation-delay, animation-iteration-count, animation-direction and animation-fill-mode.
Timing Functions
The timing function controls the acceleration curve of your animation. CSS provides several built-in options.
ease(default) starts slow, speeds up, then slows down at the end.linearmaintains constant speed throughout.ease-instarts slow and accelerates.ease-outstarts fast and decelerates. Great for elements entering the viewport.ease-in-outcombines ease-in and ease-out for smooth start and finish.cubic-bezier(x1, y1, x2, y2)lets you define a custom curve for precise control.
Custom cubic-bezier values are useful for bouncy or spring-like effects. For example, cubic-bezier(0.68, -0.55, 0.27, 1.55) creates a slight overshoot and snap-back effect.
Common Animation Patterns
Fade In
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
Slide In from Left
from { transform: translateX(-100%); }
to { transform: translateX(0); }
}
Pulse / Scale
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
Rotate
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
Fill Mode and Direction
animation-fill-mode determines what styles apply before and after the animation runs. The most common value is forwards, which keeps the element in its final keyframe state after the animation ends. Without it, the element snaps back to its pre-animation state.
animation-direction controls whether the animation runs forwards, backwards or alternates. Setting alternate with infinite iteration count creates a smooth back-and-forth loop, perfect for breathing or pulsing effects.
Performance Tips
Not all CSS properties animate equally. For smooth 60fps animations, stick to properties that the browser can composite on the GPU.
- Prefer transform and opacity. These properties are composited on a separate layer and do not trigger layout recalculations or repaints.
- Avoid animating layout properties. Properties like
width,height,marginandtop/leftforce the browser to recalculate layout for the entire page on every frame. - Use will-change sparingly. Adding
will-change: transformhints to the browser to promote the element to its own layer. But overusing it wastes GPU memory, so only apply it to elements that actually animate. - Keep durations reasonable. Animations between 150ms and 500ms feel responsive. Anything over 1 second can feel sluggish unless it is a background decorative effect.
Accessibility: prefers-reduced-motion
Some users experience motion sickness or discomfort from animations. The prefers-reduced-motion media query lets you respect their system preference.
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
}
}
This removes animations for users who opt out while preserving them for everyone else. It is a small addition that significantly improves inclusivity.
Multiple Animations
You can apply multiple animations to a single element by comma-separating them. Each animation can have its own duration, delay and timing function.
animation: fadeIn 400ms ease-out,
slideUp 600ms ease-out 200ms;
}
This technique is useful for staggered entrances where you want opacity and position to animate independently with different timings.
Try it yourself
Visually build CSS animations with a live preview. Choose from common presets or customize every property, then copy the generated code.
Open CSS Animation Generator →