CSS 3 min read

CSS Animations That Don’t Hurt Performance

Smooth micro-interactions make a site feel premium; janky ones make it feel broken. Learn transitions vs keyframes, which properties are cheap to animate, and how to respect reduced-motion settings.

On this page

Key takeaways

  • Animate only transform and opacity for smooth, cheap animations.
  • Animating width, height, top or margin forces layout work on every frame and can cause jank and layout shift.
  • Respect prefers-reduced-motion and keep animations short and purposeful.

Subtle motion makes interfaces feel polished: a button that lifts on hover, a menu that slides in, a theme toggle where the sun turns into a moon. But poorly built animations drain batteries, stutter on mid-range phones and can even hurt Core Web Vitals. Here’s how to animate well.

How browsers render a frame#

  1. Style — work out which CSS applies.
  2. Layout — calculate sizes and positions.
  3. Paint — fill in pixels.
  4. Composite — combine layers on the GPU.

Changing width triggers all four steps. Changing transform or opacity usually only needs compositing, which the GPU handles easily at 60 frames per second.

Transitions vs keyframe animations#

/* Transition: animate between two states */
.card { transition: transform .3s ease, box-shadow .3s ease; }
.card:hover { transform: translateY(-4px); box-shadow: 0 12px 30px rgba(0,0,0,.15); }

/* Keyframes: multi-step or looping animation */
@keyframes pulse { 50% { opacity: .5; } }
.dot { animation: pulse 2.4s ease-in-out infinite; }

Cheap vs expensive properties#

Animate this Instead of
transform: translateX() left / margin-left
transform: scale() width / height
opacity visibility toggles with layout changes
transform: scaleX() on a bar Animating width of a progress bar

This site’s reading progress bar uses transform: scaleX() for exactly this reason.

Need a hand with this?

Get a quick, honest review of your website’s SEO.

Chat on WhatsApp

Respect reduced-motion preferences#

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

Some people experience nausea or dizziness from motion. Honouring their system setting is an accessibility requirement (WCAG 2.3.3).

Animations and Core Web Vitals#

  • Layout-changing animations on page load can count as layout shift.
  • Heavy JavaScript animation libraries add to main-thread work and can hurt INP.
  • Fade-in-on-scroll effects that start content at opacity: 0 can delay LCP if applied to the hero — keep the first screen visible immediately.

Practical guidelines#

  • Durations: 150–300 ms for UI feedback; up to ~500 ms for larger transitions.
  • Easing: ease-out or a custom cubic-bezier(.2,.8,.2,1) feels natural for entering elements.
  • Use will-change sparingly, only on elements about to animate.
  • Prefer CSS over JavaScript for simple effects; use the Web Animations API or View Transitions for more complex ones.

View Transitions#

The View Transitions API animates between page states — or even between pages on multi-page sites — with a cross-fade by default. This theme uses it for a smooth light/dark toggle in browsers that support it, falling back instantly elsewhere.

CSS animations FAQ#

Do animations hurt SEO?#

Not directly, but heavy or layout-shifting animations can worsen Core Web Vitals and user experience.

Should I use an animation library?#

For simple hover and entrance effects, plain CSS is enough. Libraries like GSAP are great for complex, timeline-based animation.

Why does my animation stutter on phones?#

Usually because it animates layout properties or large shadows/filters. Switch to transform and opacity.

Found this useful? Share it

Join the discussion

Your email address will not be published. Required fields are marked *

Security code image. If you cannot read it, press refresh or contact me on WhatsApp.