Frontend Development5 min read

CSS Animations & Transitions

Create smooth CSS animations: transitions vs keyframes, animation performance, View Transitions API, and reduced motion accessibility.

cssanimationtransitionsmotion

CSS animations and transitions enable smooth visual feedback without JavaScript. The key to performant animations is animating only GPU-composited properties (transform, opacity) and using CSS animations on the element directly rather than forcing layout recalculations.

Animate only `transform` and `opacity` for performance - these are composited by the GPU and never trigger layout or paint. Use CSS transitions for state changes (hover, active), keyframes for looping or complex sequences. Always respect `prefers-reduced-motion`.

Workflow

  1. Write performant transitionsCSS transitions automatically animate property changes between states.
  2. Create keyframe animationsKeyframes define complex multi-step animations independent of state changes.
  3. Force GPU compositingGPU-composited layers animate without involving the main thread, preventing jank.
  4. Use the View Transitions APIView Transitions enable smooth same-page and cross-page transitions with minimal code.
  5. Respect prefers-reduced-motionUsers with vestibular disorders or motion sensitivity can be harmed by animations.

Output Format

Transitions on base element (not :hover), keyframes with `both` fill-mode, transform/opacity only, `will-change` before animation, View Transitions for route changes, `prefers-reduced-motion` media query.

Examples

Performant button: `.btn { transition: transform 0.15s ease, box-shadow 0.15s ease; } .btn:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.15); } .btn:active { transform: translateY(0); box-shadow: none; }`
Page transition: `document.startViewTransition(async () => { const response = await fetch(url); document.querySelector("#content").innerHTML = await response.text(); }); ::view-transition-old(root) { animation: slide-out 0.3s ease-in forwards; } ::view-transition-new(root) { animation: slide-in 0.3s ease-out forwards; }`
Reduced motion: `@media (prefers-reduced-motion: no-preference) { .notification { animation: bounce 0.5s ease; } } @media (prefers-reduced-motion: reduce) { .notification { animation: fade 0.2s ease; } /* simple fade instead of bounce */}`

Edge Cases & Gotchas

  • FLIP technique: for animating layout changes (reordering, expanding), use FLIP (First-Last-Invert-Play) with Web Animations API - capture start/end positions, then animate transform between them instead of layout properties
  • View Transitions cross-origin: only same-origin navigation qualifies; cross-origin navigations never trigger view transitions
  • `will-change` leak: forgetting to remove `will-change` after animation creates persistent compositing layers - memory cost with no benefit

When to Break These Rules

  • For complex, timeline-based animations with multiple coordinated elements (character animation, infographics), use GSAP - it's purpose-built for this and handles cross-browser quirks.

Reference Files

  • View Transitions API: https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API
  • CSS Animations: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animations
  • GPU compositing: https://web.dev/articles/animations-guide
  • Reduced motion: https://web.dev/articles/prefers-reduced-motion

More skills in this library

Browse all technical skills - Mobile, AI/ML, Web, Backend, Design, and Product.