CSS animations allow you to create complex, multi-step animations using keyframes. Unlike transitions that only animate between two states, animations can have multiple intermediate steps, run automatically on page load, loop infinitely, and even run in reverse. With @keyframes and animation properties, you can create everything from subtle loading spinners to elaborate animated sequences—all without JavaScript.
Animations vs Transitions
Understanding when to use animations versus transitions is crucial for effective motion design.
Transitions
- Two states (start and end)
- Require a trigger (hover, focus, class change)
- Automatic reverse animation
- Simple, straightforward
- Best for: Interactive effects, hover states
Animations
- Multiple states (keyframes)
- Can run automatically (no trigger needed)
- Fine control over every step
- Can loop, reverse, delay
- Best for: Loading spinners, attention grabbers, sequences
Simple Rule: Use transitions for user-triggered changes (hover, focus). Use animations for automatic effects (loading, pulsing, continuous motion) or when you need more than two states.
@keyframes - Defining Animations
@keyframes defines the steps of an animation. You specify what happens at different points in the animation timeline.
/* Basic @keyframes syntax */
@keyframes animation-name {
from {
/* Starting state (0%) */
opacity: 0;
}
to {
/* Ending state (100%) */
opacity: 1;
}
}
/* Percentage-based keyframes (more control) */
@keyframes slide-in {
0% {
transform: translateX(-100%);
opacity: 0;
}
50% {
transform: translateX(10%);
}
100% {
transform: translateX(0);
opacity: 1;
}
}
/* Multiple properties at each step */
@keyframes complex-animation {
0% {
transform: scale(1) rotate(0deg);
background: blue;
}
50% {
transform: scale(1.5) rotate(180deg);
background: red;
}
100% {
transform: scale(1) rotate(360deg);
background: blue;
}
}
/* Same values for multiple keyframes */
@keyframes pulse {
0%, 100% {
transform: scale(1);
}
50% {
transform: scale(1.1);
}
}@keyframes Examples
Animation Properties
CSS animations use multiple properties to control how keyframe animations run.
Animation Properties
| Property | Values | Description |
|---|---|---|
animation-name | Keyframe name | Which @keyframes to use |
animation-duration | Time (s or ms) | How long the animation takes |
animation-timing-function | ease, linear, etc. | Speed curve |
animation-delay | Time (s or ms) | Wait before starting |
animation-iteration-count | Number or infinite | How many times to repeat |
animation-direction | normal, reverse, alternate | Which direction to run |
animation-fill-mode | none, forwards, backwards, both | States before/after animation |
animation-play-state | running, paused | Control playback |
/* Individual properties */
.element {
animation-name: slide-in;
animation-duration: 1s;
animation-timing-function: ease;
animation-delay: 0.5s;
animation-iteration-count: infinite;
animation-direction: alternate;
animation-fill-mode: forwards;
animation-play-state: running;
}
/* Shorthand: name duration timing delay iteration direction fill-mode */
.element {
animation: slide-in 1s ease 0.5s infinite alternate forwards;
}
/* Multiple animations */
.element {
animation:
spin 2s linear infinite,
pulse 1s ease-in-out infinite alternate;
}animation-duration
animation-duration sets how long one cycle of the animation takes to complete.
/* Duration in seconds */
.element {
animation-duration: 1s; /* 1 second */
animation-duration: 2.5s; /* 2.5 seconds */
}
/* Duration in milliseconds */
.element {
animation-duration: 500ms; /* Same as 0.5s */
animation-duration: 2000ms; /* Same as 2s */
}
/* Common durations */
.fast {
animation-duration: 0.3s; /* Quick */
}
.normal {
animation-duration: 1s; /* Standard */
}
.slow {
animation-duration: 3s; /* Deliberate */
}
/* Shorthand */
.element {
animation: slide-in 1.5s;
}Animation Duration Comparison
animation-iteration-count
animation-iteration-count specifies how many times the animation should repeat.
/* Specific number of iterations */
.element {
animation-iteration-count: 1; /* Once (default) */
animation-iteration-count: 3; /* 3 times */
animation-iteration-count: 10; /* 10 times */
}
/* Infinite loop */
.element {
animation-iteration-count: infinite; /* Never stops */
}
/* Decimal values */
.element {
animation-iteration-count: 2.5; /* 2.5 times */
}
/* Common patterns */
.loading {
animation: spin 1s linear infinite; /* Continuous */
}
.attention {
animation: pulse 0.5s ease 3; /* 3 pulses */
}
/* Shorthand */
.element {
animation: slide-in 1s ease 3; /* 3 iterations */
animation: spin 2s linear infinite; /* Infinite */
}Animation Iteration Count
animation-direction
animation-direction controls whether the animation plays forward, backward, or alternates.
animation-direction Values
| Property | Values | Description |
|---|---|---|
normal | Default | Forward every iteration |
reverse | Backward | Backward every iteration |
alternate | Forward then backward | Alternates direction each iteration |
alternate-reverse | Backward then forward | Starts backward, then alternates |
/* Direction values */
.element {
animation-direction: normal; /* Default: forward */
animation-direction: reverse; /* Backward */
animation-direction: alternate; /* Forward, back, forward... */
animation-direction: alternate-reverse; /* Back, forward, back... */
}
/* Common pattern: Smooth back-and-forth */
.element {
animation: slide 2s ease-in-out infinite alternate;
/* Slides smoothly back and forth */
}
/* Shorthand */
.element {
animation: slide 2s linear infinite alternate;
}Animation Direction
🔄 Alternate Direction Tip:
alternate is perfect for smooth back-and-forth animations like floating buttons, pulsing elements, or swaying objects. It creates seamless loops without jarring resets.
animation-fill-mode
animation-fill-mode controls what styles apply before the animation starts and after it ends.
animation-fill-mode Values
| Property | Values | Description |
|---|---|---|
none | Default | No styles before/after animation |
forwards | Keep end state | Retains final keyframe styles |
backwards | Apply start state during delay | Applies first keyframe during delay |
both | Both forwards and backwards | Combines forwards and backwards |
/* Fill mode values */
.element {
animation-fill-mode: none; /* Default */
animation-fill-mode: forwards; /* Keep final state */
animation-fill-mode: backwards; /* Apply start during delay */
animation-fill-mode: both; /* Both forwards and backwards */
}
/* Common pattern: Keep animation end state */
.fade-in {
opacity: 0;
animation: fadeIn 1s ease forwards;
/* Stays at opacity: 1 after animation */
}
@keyframes fadeIn {
to {
opacity: 1;
}
}
/* With delay: Apply start state immediately */
.slide-in {
animation: slideIn 1s ease 2s backwards;
/* Shows starting position during 2s delay */
}
/* Shorthand */
.element {
animation: fadeIn 1s ease forwards;
}Animation Fill Mode
Practical Animation Examples
Loading Spinners
Loading Spinners
Attention Grabbers
Attention-Grabbing Animations
Page Entrance Animations
Entrance Animations
Animation Performance
Performance Best Practices
- Animate transform and opacity only: These are GPU-accelerated
- Avoid animating: width, height, top, left, margin, padding
- Use will-change sparingly:
will-change: transform;hints optimization - Limit simultaneous animations: Too many can cause jank
- Use animation-play-state: Pause animations when off-screen
- Test on mobile: Slower devices struggle with complex animations
/* Good: GPU-accelerated */
@keyframes goodAnimation {
from {
transform: translateX(0);
opacity: 0;
}
to {
transform: translateX(100px);
opacity: 1;
}
}
/* Avoid: Triggers layout recalculation */
@keyframes badAnimation {
from {
left: 0; /* Avoid */
width: 100px; /* Avoid */
}
to {
left: 100px; /* Avoid */
width: 200px; /* Avoid */
}
}
/* Use will-change for complex animations */
.complex {
will-change: transform, opacity;
animation: complex 2s ease;
}
/* Pause off-screen animations */
.element {
animation-play-state: running;
}
.element.off-screen {
animation-play-state: paused;
}Key Takeaways
- @keyframes: Define multi-step animations
- Percentages: 0%, 50%, 100% for precise control
- animation-duration: How long one cycle takes
- animation-iteration-count: Number or infinite
- animation-direction: normal, reverse, alternate
- animation-fill-mode: forwards keeps final state
- Animations can run automatically (no trigger needed)
- Multiple properties can change at each keyframe
- Shorthand: name duration timing delay iteration direction fill-mode
- Only animate transform and opacity for best performance
- Use alternate for smooth back-and-forth effects
- Stagger delays for sequential animations
What's Next?
Now that you understand CSS animations and keyframes, you're ready to learn about Filters and Blend Modes. In the next lesson, we'll explore visual effects like blur, brightness, contrast, and blend modes that add artistic polish to images and elements.
CSS animations are incredibly powerful for creating engaging user experiences. From subtle loading spinners to elaborate entrance effects, animations bring your designs to life. Practice combining transforms with opacity in your keyframes, and remember: keep performance in mind by animating GPU-accelerated properties!