← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

requestAnimationFrame — Smooth Animations

javascript HTML5 Intermediate

Also Known As

requestAnimationFrame rAF animation loop browser repaint

TL;DR

requestAnimationFrame(callback) schedules a function to run before the browser's next repaint — the correct way to animate in JavaScript, producing smooth 60fps motion and automatically pausing when the tab is hidden.

Explanation

Before requestAnimationFrame, animations used setTimeout or setInterval with fixed millisecond delays. These ignore the monitor's refresh rate, fire at inconsistent intervals, and continue running in background tabs wasting CPU. requestAnimationFrame synchronises with the browser's render cycle — typically 60fps on most displays, 120fps on high-refresh screens. The callback receives a DOMHighResTimeStamp argument giving the current time, enabling frame-rate-independent animation. When the tab is not visible, the browser throttles or stops rAF calls entirely. cancelAnimationFrame() cancels a pending callback. For complex animations, the Web Animations API or CSS transitions are often preferable — they can run on the compositor thread without blocking the main thread.

Common Misconception

requestAnimationFrame guarantees exactly 60fps. It runs once per repaint cycle — on a 144Hz monitor that is 144 times per second; on a throttled background tab it may run at 1fps. Write animations based on the elapsed time argument, not on assumed frame rate.

Why It Matters

setTimeout-based animation produces visible jank because it fires independently of the display's refresh cycle — frames are dropped or doubled. requestAnimationFrame ties animation to the actual screen refresh, producing smooth motion. It also enables automatic performance optimisation: pausing when the tab is not visible saves battery and CPU.

Common Mistakes

  • Not using the timestamp argument — hardcoding speed as 'pixels per frame' makes animation fast on 144Hz and slow on 30Hz; always use elapsed time.
  • Forgetting to store and cancel the animation ID — rAF loops that are never cancelled continue running even after components are removed, causing memory leaks.
  • Calling rAF from inside a resize event handler — creates multiple parallel animation loops; keep one loop and handle resize state separately.
  • Doing heavy computation inside the rAF callback — long tasks block the main thread and skip frames; offload to Web Workers and only do drawing inside rAF.

Code Examples

✗ Vulnerable
// ❌ setInterval animation — ignores refresh rate, runs in background
let x = 0;
setInterval(() => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillRect(x++, 50, 20, 20);
    // Runs every 16ms regardless of monitor refresh rate
    // Continues running in background tab — wastes battery
    // No sync with display — produces tearing/jank
}, 16);
✓ Fixed
// ✅ requestAnimationFrame — synced to display, time-based movement
let x = 0;
let lastTime = null;
let animId = null;

function draw(timestamp) {
    if (lastTime === null) lastTime = timestamp;
    const elapsed = timestamp - lastTime; // ms since last frame
    lastTime = timestamp;

    const speed = 200; // pixels per second — frame-rate independent
    x += speed * (elapsed / 1000);

    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillRect(x % canvas.width, 50, 20, 20);

    animId = requestAnimationFrame(draw);
}

// Start
animId = requestAnimationFrame(draw);

// Stop when needed (e.g. component unmount)
function stop() { cancelAnimationFrame(animId); }

Added 23 Mar 2026
Edited 5 Apr 2026
Views 25
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 0 pings T 0 pings F 0 pings S 2 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 2 pings S 0 pings M 0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T
No pings yet today
No pings yesterday
Amazonbot 8 Perplexity 5 Google 3 ChatGPT 1 Majestic 1 Meta AI 1 Ahrefs 1
crawler 20
DEV INTEL Tools & Severity
⚙ Fix effort: Low
⚡ Quick Fix
Replace setInterval(draw, 16) with function loop(t) { draw(t); requestAnimationFrame(loop); } requestAnimationFrame(loop). Use the timestamp argument for time-based animation instead of assuming fixed frame rate.
📦 Applies To
javascript HTML5 web

✓ schema.org compliant