Skip to main content

CSS Animations & Transitions: Everything You Need to Know

Master CSS animations and transitions for smooth, performant web interactions and visual effects

Overview

Category:UI FUNDAMENTALS
Difficulty:INTERMEDIATE
Last Updated:2025-09-21
Tags:
cssanimationstransitionskeyframesperformanceuxmotion

Master CSS animations and transitions for smooth, performant web interactions and visual effects

Reference Content

Understanding Motion in CSS

Transitions vs Animations:

  • Transitions: Smooth change between two states (hover, focus, class change). Perfect for micro-interactions.
  • Animations: Complex, multi-step sequences that can loop and reverse. Ideal for attention-grabbing effects.
Performance Impact: Motion should enhance, not hinder. Stick to GPU-accelerated properties (transform, opacity) for 60fps smoothness.

Transitions

What it does: Smoothly animates property changes over time instead of instant jumps. Why use it: Creates polished, professional interfaces. Users perceive smooth transitions as higher quality. How it works:
1. Browser detects property change (hover, class addition, etc.)
2. Calculates intermediate values between start and end states
3. Updates property gradually over specified duration

.element {
/ Shorthand: property duration timing-function delay /
transition: opacity 0.3s ease-in-out 0s;

/ Individual properties /
transition-property: opacity;
transition-duration: 0.3s;
transition-timing-function: ease-in-out;
transition-delay: 0s;

/ Multiple properties /
transition: opacity 0.3s, transform 0.5s;

/ All properties /
transition: all 0.3s ease;
}

Animations

/ Basic keyframes /
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}

/ Percentage-based keyframes /
@keyframes slide-bounce {
0% {
transform: translateX(0);
}
25% {
transform: translateX(100px);
}
50% {
transform: translateX(100px) translateY(-20px);
}
75% {
transform: translateX(100px) translateY(0);
}
100% {
transform: translateX(0);
}
}

Common Animation Patterns

.spinner {
width: 40px;
height: 40px;
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
}

@keyframes spin {
to { transform: rotate(360deg); }
}

Performance Optimization

What it does: Offloads animations to GPU, achieving 60fps even on complex animations. Why it matters: Janky animations frustrate users and make apps feel broken. GPU acceleration = smooth motion. How it works:

  • GPU handles: transform, opacity, filter
  • CPU handles: width, height, top, left, margin, padding
  • GPU creates compositor layers for animated elements
/ ✅ GOOD - GPU accelerated properties /
.performant {
transform: translateX(100px); / Position via transform /
opacity: 0.5; / Transparency /
filter: blur(5px); / Visual effects /
/ These run at 60fps without affecting other elements /
}

/ ❌ AVOID - Triggers expensive layout/paint /
.expensive {
left: 100px; / Forces layout recalculation /
width: 200px; / All elements must reflow /
height: 100px; / Entire page might repaint /
/ These cause "layout thrashing" - major performance hit /
}

/ Real example: Sliding panel /
/ ❌ Bad - animates 'left' property /
.panel-slow {
position: absolute;
left: -300px;
transition: left 0.3s;
}
.panel-slow.open {
left: 0;
}

/ ✅ Good - animates 'transform' /
.panel-fast {
transform: translateX(-300px);
transition: transform 0.3s;
}
.panel-fast.open {
transform: translateX(0);
}

Common pitfall: Animating width/height for accordions. Use max-height or scale transform instead. Performance test: Chrome DevTools > Rendering tab > Enable "Paint flashing" to see what's repainting.

Interactive Examples

.flip-card {
width: 300px;
height: 200px;
perspective: 1000px;
}

.flip-card-inner {
position: relative;
width: 100%;
height: 100%;
transition: transform 0.6s;
transform-style: preserve-3d;
}

.flip-card:hover .flip-card-inner {
transform: rotateY(180deg);
}

.flip-card-front, .flip-card-back {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
}

.flip-card-back {
transform: rotateY(180deg);
}

Animation State Management

.video-animation {
animation: rotate 2s linear infinite;
animation-play-state: paused;
}

.playing .video-animation {
animation-play-state: running;
}

Accessibility Considerations

What it does: Detects if users have requested reduced motion in their OS settings. Why it matters: Motion can trigger vestibular disorders, migraines, and motion sickness. It's not just preference - it's accessibility. How to implement: Provide alternatives, not just removal. Replace motion with fades or instant changes.

/ Method 1: Nuclear option - remove all motion /
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}

/ Method 2: Better - provide alternatives /
.card {
animation: slideUp 0.5s ease;
}

@media (prefers-reduced-motion: reduce) {
.card {
animation: fadeIn 0.2s ease; / Gentler alternative /
}
}

/ Method 3: Best - design with preference in mind /
.animated-element {
/ Default: subtle motion /
transform: scale(1);
transition: transform 0.2s ease;
}

.animated-element:hover {
transform: scale(1.05); / Small, purposeful /
}

@media (prefers-reduced-motion: no-preference) {
/ Enhance for those who want motion /
.animated-element {
transition: transform 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
.animated-element:hover {
transform: scale(1.1) rotate(5deg);
}
}

Testing:
  • macOS: System Preferences > Accessibility > Display > Reduce motion
  • Windows: Settings > Ease of Access > Display > Show animations
  • Chrome DevTools: Rendering tab > Emulate CSS media feature prefers-reduced-motion
Real-world impact: iOS automatically reduces parallax and animations when enabled. Major sites like GitHub respect this setting.