DEV Community

Cover image for πŸƒπŸ»β€β™‚οΈβ€βž‘οΈ Smooth, Jank-Free Animations with CSS and JavaScript: Performance Best Practices
Anisubhra Sarkar (Ani)
Anisubhra Sarkar (Ani)

Posted on • Edited on

πŸƒπŸ»β€β™‚οΈβ€βž‘οΈ Smooth, Jank-Free Animations with CSS and JavaScript: Performance Best Practices

Creating smooth, high-performance animations is essential for delivering great user experiences in modern web applications. Laggy or janky animations can frustrate users and hurt your app's perceived quality.

This guide will walk you through best practices for performant animations in CSS and JavaScript, cover tools like GSAP and Framer Motion, and highlight common pitfalls to avoid.


What Makes an Animation Performant?

To ensure your animations feel smooth and consistent at 60 FPS (or higher), keep these fundamentals in mind:

1. Leverage GPU (Hardware Acceleration)

Modern browsers can offload rendering to the GPUβ€Šβ€”β€Šbut only if you animate the right properties.
The key is to stick with:

  • transform
  • opacity

These are GPU-accelerated properties and won’t trigger costly reflows or repaints.

2. Avoid Layout Thrashing (Reflow & Repaint)

Some CSS properties are expensive because they trigger layout recalculations and painting. Avoid animating:

  • width, height, top, left, margin
  • background-color, box-shadow (when done excessively)

βœ… Instead:
Use transform: translate() instead of top/left, and animate opacity instead of toggling visibility.


Why Only transform and opacity Are GPU-Accelerated

When something on the page changes, the browser goes through a rendering pipeline:

Browser rendering pipeline: JavaScript execution β†’ Style recalculation β†’ Layout (reflow) β†’ Paint β†’ Composite

  • Main Thread: Handles JavaScript, layout, and style recalculation.
  • Compositor Thread: Responsible for painting layers and compositing.
  • GPU Thread: Handles hardware-accelerated drawing.

βœ… Animating transform and opacity only affects the compositing stage, bypassing layout and paint.
❌ Animating properties like top or width forces recalculation of layout and paint, blocking the main thread.

Here’s a breakdown of CSS properties and their performance impact:

CSS properties categorized by their rendering impact: some trigger layout and reflow (e.g., width, height, margin), others trigger paint (e.g., background, color, shadows), and some only affect compositing (e.g., transform, opacity)


CSS Animations: First Choice for UI Effects

For simple interactions, CSS transitions and keyframes are your best bet.

Example: Hover Animation (GPU-Friendly)

.box {
  transition: transform 0.3s ease-out, opacity 0.3s ease-in;
}

.box:hover {
  transform: scale(1.1);
  opacity: 0.8;
}
Enter fullscreen mode Exit fullscreen mode

βœ” This works smoothly because it only animates transform and opacity.


Pro Tip: Use will-change (But Wisely)

.box {
  will-change: transform, opacity;
}
Enter fullscreen mode Exit fullscreen mode

will-change hints to the browser that an element will change soon, so it can optimize rendering ahead of time.

⚠️ Don’t overuse it β€” reserving GPU layers unnecessarily can hurt performance.


JavaScript Animations: When You Need More Control

For complex animations, JavaScript with requestAnimationFrame() is the way to go.

Example: Smooth Movement

function animateBox() {
  const box = document.getElementById("box");
  let start = null;

  function step(timestamp) {
    if (!start) start = timestamp;
    const progress = timestamp - start;

    box.style.transform = `translateX(${Math.min(progress / 5, 300)}px)`;

    if (progress < 1500) {
      requestAnimationFrame(step);
    }
  }

  requestAnimationFrame(step);
}

document.getElementById("start").addEventListener("click", animateBox);
Enter fullscreen mode Exit fullscreen mode

βœ” requestAnimationFrame() syncs with the browser’s rendering cycle, reducing jank.


Why Not setInterval() for Animations?

  • ❌ Runs on fixed intervals (not synced to refresh rate).
  • ❌ Keeps running in inactive tabs, wasting resources.
  • ❌ Causes stutters under heavy load.

βœ… requestAnimationFrame() adapts to the refresh cycle and pauses in inactive tabs.


Animation Libraries You Should Know

GSAP (GreenSock Animation Platform)

  • High-performance, widely used.
  • Handles browser quirks and optimizations.
gsap.to(".box", { x: 300, duration: 1, ease: "power2.out" });
Enter fullscreen mode Exit fullscreen mode

βœ” Best for: complex timelines, SVG animations, and cross-browser consistency.


Framer Motion (for React)

  • Declarative, React-first animation library.
  • Works seamlessly with React components.
import { motion } from "framer-motion";

const Box = () => (
  <motion.div animate={{ x: 100 }} transition={{ duration: 0.5 }} />
);
Enter fullscreen mode Exit fullscreen mode

βœ” Best for: React apps, UI interactions, and component-based motion.


Which Animation Tool to Use When?

  • CSS Transitions/Keyframes β†’ Simple hover, fade, or UI effects.
  • JavaScript (requestAnimationFrame) β†’ Custom logic, physics-based movement.
  • GSAP β†’ Complex animations, timelines, SVGs, cross-browser needs.
  • Framer Motion β†’ React-based UIs needing declarative animations.

Final Takeaways

  • Use transform and opacity for smooth, GPU-accelerated animations.
  • Avoid layout-thrashing properties like width and top.
  • Prefer CSS for simple effects, JS for complex logic.
  • Reach for GSAP or Framer Motion when building interactive, production-grade animations.

Top comments (0)