What You'll Learn
How to define animations with @keyframes
Using animation properties to control playback
Creating basic animations: fade, slide, spin
Building multi-step animations with percentage keyframes
Understanding timing functions and their effects
Controlling animation duration, delay, and iteration
Using animation-direction and fill-mode
Creating practical effects: loading spinners, pulses, shakes
Introduction to CSS Animations
CSS animations allow you to animate HTML elements without JavaScript by defining keyframes—intermediate steps between states.
Unlike transitions which require a trigger (like :hover), animations can run automatically when the page loads or loop infinitely.
Animations are defined using the @keyframes at-rule, which specifies what should happen at different points
during the animation sequence. You then apply these animations to elements using the animation property.
Animations vs Transitions: Use transitions for simple state changes (hover, focus). Use animations for
complex, multi-step sequences that need precise control or should run automatically.
Basic Animations
Let's start with three fundamental animations: fade in, slide in, and spin. Each demonstrates the basic structure
of defining keyframes and applying an animation.
/* Fade animation */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
/* Slide animation */
@keyframes slideIn {
from { transform: translateX(-100px); }
to { transform: translateX(0); }
}
/* Spin animation */
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* Apply animations */
.fade-in {
animation: fadeIn 2s ease-in-out infinite alternate;
}
.slide-in {
animation: slideIn 1.5s ease-out infinite;
}
.spin {
animation: spin 2s linear infinite;
}
Keyframe Syntax: You can use from and to for simple two-step animations,
or percentage values (0%, 50%, 100%) for multi-step sequences.
Multi-Step Animations
Multi-step animations use percentage keyframes to create more complex motion. You can define as many intermediate
steps as needed to achieve the desired effect.
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-50px); }
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.2); }
}
@keyframes shake {
0%, 100% { transform: translateX(0); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-10px); }
20%, 40%, 60%, 80% { transform: translateX(10px); }
}
.bounce { animation: bounce 1s ease-in-out infinite; }
.pulse { animation: pulse 1s ease-in-out infinite; }
.shake { animation: shake 0.8s ease-in-out infinite; }
Color Animations
You can animate any CSS property that accepts numeric or color values. Background colors and gradients
can create eye-catching effects.
@keyframes colorChange {
0% { background: #3b82f6; }
33% { background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); }
66% { background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); }
100% { background: #3b82f6; }
}
.color-change {
animation: colorChange 4s ease-in-out infinite;
}
Performance: Animating colors is less performant than animating transform or
opacity. Use sparingly and test on lower-end devices.
Timing Functions
The animation-timing-function controls the acceleration curve of the animation. Different timing
functions create different "feels" for your animations.
@keyframes move {
to { transform: translateX(150px); }
}
.timing-linear { animation: move 2s linear infinite alternate; }
.timing-ease { animation: move 2s ease infinite alternate; }
.timing-ease-in { animation: move 2s ease-in infinite alternate; }
.timing-ease-out { animation: move 2s ease-out infinite alternate; }
.timing-ease-in-out { animation: move 2s ease-in-out infinite alternate; }
/* Custom cubic-bezier for bounce effect */
.timing-custom {
animation: move 2s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite alternate;
}
Timing Function Guide:
linear - Constant speed, mechanical feeling
ease - Slow start, fast middle, slow end (most natural)
ease-in - Slow start, accelerates
ease-out - Fast start, decelerates (good for entrances)
ease-in-out - Slow start and end
cubic-bezier() - Custom curve for unique effects
Complex Animations
Combine multiple properties in keyframes to create sophisticated animations. You can animate transform,
opacity, and other properties simultaneously.
@keyframes complex {
0% {
transform: translateX(0) rotate(0deg);
opacity: 1;
}
25% {
transform: translateX(80px) rotate(90deg);
opacity: 0.7;
}
50% {
transform: translateX(80px) translateY(40px) rotate(180deg);
opacity: 0.4;
}
75% {
transform: translateX(0) translateY(40px) rotate(270deg);
opacity: 0.7;
}
100% {
transform: translateX(0) rotate(360deg);
opacity: 1;
}
}
.complex {
animation: complex 4s ease-in-out infinite;
}
Animation Properties
The animation property is a shorthand for eight individual properties that control every aspect
of the animation playback.
/* Individual properties */
.element {
animation-name: spin;
animation-duration: 2s;
animation-timing-function: ease-in-out;
animation-delay: 1s;
animation-iteration-count: infinite; /* or number */
animation-direction: normal; /* normal, reverse, alternate, alternate-reverse */
animation-fill-mode: forwards; /* none, forwards, backwards, both */
animation-play-state: running; /* running, paused */
}
/* Shorthand syntax */
.element {
animation: spin 2s ease-in-out 1s infinite alternate forwards;
/* name duration timing delay iteration direction fill-mode */
}
Animation Properties:
animation-name - References the @keyframes name
animation-duration - How long one cycle takes
animation-timing-function - Acceleration curve
animation-delay - Wait before starting
animation-iteration-count - How many times to repeat
animation-direction - Forward, reverse, or alternating
animation-fill-mode - Style before/after animation
animation-play-state - Pause or resume animation
Play State Control
The animation-play-state property allows you to pause and resume animations, often used with
interactive elements.
.paused {
animation: spin 2s linear infinite;
animation-play-state: paused;
}
.paused:hover {
animation-play-state: running;
}
Loading Spinner
A practical example: creating a loading spinner with a single div and CSS animation. This is a common UI pattern
for loading states.
.loader {
width: 50px;
height: 50px;
border: 5px solid #f3f3f3;
border-top: 5px solid #667eea;
border-radius: 50%;
animation: loader 1s linear infinite;
}
@keyframes loader {
to { transform: rotate(360deg); }
}
Spinner Variations: Try changing the border colors, using multiple colored borders, or
applying different timing functions for unique effects.
Multiple Animations
You can apply multiple animations to a single element by separating them with commas. Each animation runs independently.
@keyframes rotate {
to { transform: rotate(360deg); }
}
@keyframes changeColor {
0% { background: #ef4444; }
50% { background: #3b82f6; }
100% { background: #ef4444; }
}
.multi-animation {
animation:
rotate 3s linear infinite,
changeColor 2s ease-in-out infinite;
}
Key Takeaways
@keyframes: Define animation sequences using from/to or percentage values
Automatic Playback: Unlike transitions, animations can start automatically without a trigger
Multi-Step Control: Create complex motion with multiple keyframe steps
Timing Functions: Use ease, linear, ease-in-out, or custom cubic-bezier() curves
Infinite Loops: Set animation-iteration-count: infinite for continuous animations
Direction Control: Use alternate to make animations play forward then backward
Play State: Pause and resume animations with animation-play-state
Performance: Animate only GPU-accelerated properties (transform, opacity) for 60fps
Accessibility: Always respect prefers-reduced-motion media query