Animations & Transitions

Smooth animations and interactive effects

CSS Transitions vs Animations

Transitions animate property changes from one state to another (usually triggered by hover, focus, or class change). Animations use keyframes to define complex, multi-step animations that can run automatically or loop infinitely.

Transitions: Simple A → B

Animate between two states smoothly

Animations: Complex Sequences

Multi-step animations with keyframes

CSS Transitions

Transitions make property changes smooth instead of instant. Try hovering over these examples:

Basic Button Transition

.button {
  background: #3b82f6;
  transition: all 0.3s ease;
}
.button:hover {
  background: #2563eb;
  transform: scale(1.05);
}

Multiple Properties

.box-1 {
  transition: all 0.5s ease;
}
.box-1:hover {
  border-radius: 50%;
  background: #9333ea;
  transform: rotate(180deg);
}

.box-2 {
  transition: width 0.7s ease;
}
.box-2:hover {
  width: 200px;
}

Timing Functions

Timing functions control the speed curve of animations:

linear
ease (default)
ease-in (slow start)
ease-out (slow end)
ease-in-out

Hover over the colored boxes to see timing differences

CSS Keyframe Animations

Keyframes define complex animations with multiple stages:

Basic Keyframe Animation

Fading In...
@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.element {
  animation: fadeIn 2s ease-out;
}

Common Animation Patterns

Loading Spinner

@keyframes spin {
  to { transform: rotate(360deg); }
}
.spinner {
  animation: spin 1s linear infinite;
}

Bounce Animation

@keyframes bounce {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-20px); }
}
.bounce {
  animation: bounce 0.6s ease infinite;
}

Shake Animation

@keyframes shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-10px); }
  75% { transform: translateX(10px); }
}
.error { animation: shake 0.3s ease; }

Pulse Animation

@keyframes pulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.1); }
}
.pulse {
  animation: pulse 1.5s ease infinite;
}

Skeleton Loading Effect

@keyframes shimmer {
  0% { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}
.skeleton {
  background: linear-gradient(
    90deg,
    #f0f0f0 25%,
    #e0e0e0 50%,
    #f0f0f0 75%
  );
  background-size: 200% 100%;
  animation: shimmer 1.5s infinite;
}

Transform Property

The transform property is the most performant way to animate movement, rotation, and scaling:

Translate (Move)

transform: translateX(50px);
transform: translateY(50px);

Rotate

transform: rotate(45deg);

Scale

transform: scale(1.5);

Combined

transform: translateX(16px) 
  rotate(12deg) scale(1.1);

Animation Properties

/* Animation timing */
animation-duration: 1s;
animation-delay: 0.5s;

/* Iteration */
animation-iteration-count: 1;       /* once */
animation-iteration-count: 3;       /* 3 times */
animation-iteration-count: infinite; /* forever */

/* Direction */
animation-direction: normal;         /* 0% → 100% */
animation-direction: reverse;        /* 100% → 0% */
animation-direction: alternate;      /* ping-pong */

/* Fill mode (what happens before/after) */
animation-fill-mode: none;      /* reset after */
animation-fill-mode: forwards;  /* keep end state */
animation-fill-mode: backwards; /* apply start before delay */
animation-fill-mode: both;      /* both */

/* Shorthand */
animation: fadeIn 1s ease-out 0.5s forwards;

⚡ Performance Tips

  • ✓ DO animate: transform and opacity (GPU accelerated, 60fps)
  • ✗ DON'T animate: width, height, margin, padding, top, left (causes reflow)
  • Use will-change sparingly: will-change: transform; only for complex animations
  • Reduce motion: Respect prefers-reduced-motion for accessibility

Accessibility: Reduced Motion

Some users have vestibular disorders and need reduced motion. Always respect this preference:

/* Respect user preference */
@media (prefers-reduced-motion: reduce) {
  *,

  
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* Or per-element */
@media (prefers-reduced-motion: reduce) {
  .animated-element {
    animation: none;
  }
}

✓ Animation Best Practices

  • • Keep animations subtle and purposeful—less is more
  • • Use 200-500ms for UI transitions, 1000-2000ms for attention-grabbing animations
  • • Only animate transform and opacity for smooth 60fps performance
  • • Always provide prefers-reduced-motion alternatives
  • • Use ease-out for entrances, ease-in for exits
  • • Test animations on lower-end devices