requestAnimationFrame
This lesson explains requestAnimationFrame with clear examples, use cases, and best practices so you can use HTML5 APIs confidently in real web applications.
HTML5 requestAnimationFrame API Overview
The HTML5 requestAnimationFrame() API allows JavaScript to
run animation code before the browser performs the next repaint. It is the
recommended way to create smooth animations, canvas games, visual effects,
sliders, counters, progress indicators, scroll effects, and custom UI
motion in modern web applications.
Unlike setTimeout() or setInterval(),
requestAnimationFrame() is synchronized with the browser's
refresh rate. This improves animation smoothness, avoids unnecessary work,
and helps the browser pause animations when the page is not visible.
| Feature | Description |
| API Name | requestAnimationFrame API |
| Main Method | requestAnimationFrame() |
| Cancel Method | cancelAnimationFrame() |
| Callback Timing | Runs before the next browser repaint. |
| Best Use | Smooth animations, canvas rendering, game loops, UI motion. |
| Related APIs | Canvas API, Performance API, Web Animations API, CSS Transitions. |
Basic requestAnimationFrame Example
// HTML5 requestAnimationFrame API
function animate(timestamp) {
console.log(
"Animation frame:",
timestamp
);
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
The callback receives a high-resolution timestamp. Calling
requestAnimationFrame() again inside the callback creates a
continuous animation loop.
How requestAnimationFrame Works
| Step | Description | Example Syntax |
| Create Callback | Define animation logic in a function. | function animate(time) { ... } |
| Schedule Frame | Ask browser to run callback before next repaint. | requestAnimationFrame(animate) |
| Read Timestamp | Use timestamp to calculate smooth motion. | timestamp |
| Update UI | Change transform, opacity, canvas, or visual state. | element.style.transform |
| Continue Loop | Request another frame if animation should continue. | requestAnimationFrame(animate) |
| Cancel Frame | Stop scheduled animation when no longer needed. | cancelAnimationFrame(id) |
requestAnimationFrame Methods
| Method | Description | Example Syntax |
requestAnimationFrame() | Schedules an animation callback before the next repaint. | requestAnimationFrame(callback) |
cancelAnimationFrame() | Cancels a scheduled animation frame. | cancelAnimationFrame(frameId) |
performance.now() | Provides precise timing for custom animations. | performance.now() |
Move Element Smoothly
<div id="box">
Move Me
</div>
<script>
const box =
document.querySelector("#box");
let position = 0;
function animate() {
position += 2;
box.style.transform =
"translateX(" + position + "px)";
if (position < 300) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);
</script>
This example moves an element horizontally until it reaches 300 pixels.
Using transform is usually better for animation performance
than changing layout-heavy properties such as left.
Time-Based Animation Example
const box =
document.querySelector("#box");
let startTime = null;
const duration = 1000;
const distance = 300;
function animate(timestamp) {
if (!startTime) {
startTime = timestamp;
}
const elapsed =
timestamp - startTime;
const progress =
Math.min(elapsed / duration, 1);
const position =
progress * distance;
box.style.transform =
"translateX(" + position + "px)";
if (progress < 1) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);
Time-based animation makes movement consistent across devices with
different refresh rates.
Cancel Animation Frame
let frameId = null;
function animate() {
console.log("Running animation");
frameId =
requestAnimationFrame(animate);
}
document
.querySelector("#start")
.addEventListener("click", () => {
frameId =
requestAnimationFrame(animate);
});
document
.querySelector("#stop")
.addEventListener("click", () => {
cancelAnimationFrame(frameId);
});
Use cancelAnimationFrame() to stop animations when users
pause, close, hide, or leave animated UI.
Canvas Animation Example
const canvas =
document.querySelector("#gameCanvas");
const context =
canvas.getContext("2d");
let x = 0;
function draw() {
context.clearRect(
0,
0,
canvas.width,
canvas.height
);
context.beginPath();
context.arc(
x,
80,
20,
0,
Math.PI * 2
);
context.fill();
x += 2;
if (x < canvas.width) {
requestAnimationFrame(draw);
}
}
requestAnimationFrame(draw);
Canvas games and visualizations commonly use
requestAnimationFrame() for rendering loops.
Basic Game Loop Pattern
let lastTime = 0;
function gameLoop(timestamp) {
const deltaTime =
timestamp - lastTime;
lastTime =
timestamp;
update(deltaTime);
render();
requestAnimationFrame(gameLoop);
}
function update(deltaTime) {
console.log(
"Update game state:",
deltaTime
);
}
function render() {
console.log("Render frame");
}
requestAnimationFrame(gameLoop);
Game loops separate updating state from rendering frames. The
deltaTime value helps make movement and physics independent
from frame rate.
Animated Progress Bar Example
const progressBar =
document.querySelector("#progress");
let startTime = null;
const duration = 2000;
function animateProgress(timestamp) {
if (!startTime) {
startTime = timestamp;
}
const progress =
Math.min(
(timestamp - startTime) / duration,
1
);
progressBar.style.width =
progress * 100 + "%";
progressBar.setAttribute(
"aria-valuenow",
Math.round(progress * 100)
);
if (progress < 1) {
requestAnimationFrame(animateProgress);
}
}
requestAnimationFrame(animateProgress);
Animation can update both visual styles and accessibility attributes such
as aria-valuenow.
Respect Reduced Motion Preference
const prefersReducedMotion =
window.matchMedia(
"(prefers-reduced-motion: reduce)"
).matches;
if (!prefersReducedMotion) {
requestAnimationFrame(animate);
} else {
console.log(
"Reduced motion enabled. Skip animation."
);
}
Always respect users who prefer reduced motion. Provide instant state
changes or simpler transitions instead of large animated movement.
requestAnimationFrame vs setTimeout vs setInterval
| Feature | requestAnimationFrame | setTimeout / setInterval |
| Best For | Visual animation and rendering. | Delayed or repeated non-visual tasks. |
| Repaint Sync | Runs before browser repaint. | Not synchronized with repaint. |
| Hidden Tabs | Usually paused or throttled. | May still run, but often throttled. |
| Smoothness | Better for animation. | Can cause jank or missed frames. |
| Timestamp | Receives high-resolution timestamp. | No automatic animation timestamp. |
Common requestAnimationFrame Use Cases
- Custom UI animations.
- Canvas games and visualizations.
- Progress bars and counters.
- Scroll-based visual updates.
- Physics simulations.
- Drag and resize animations.
- Chart animations.
- Animated dashboards and data visualizations.
requestAnimationFrame Best Practices
- Use
requestAnimationFrame() for visual updates. - Use
setTimeout() for delays that are not animation-related. - Use the timestamp argument for smooth time-based motion.
- Store frame IDs so animations can be cancelled.
- Respect
prefers-reduced-motion. - Keep each frame lightweight to avoid jank.
- Clean up animations when components unmount or pages change.
- Prefer CSS animations for simple state transitions when possible.
Common requestAnimationFrame Mistakes
- Using
setInterval() for smooth visual animations. - Forgetting to call
requestAnimationFrame() again inside a loop. - Not cancelling animations when no longer needed.
- Using frame count instead of elapsed time for movement.
- Running heavy calculations on every frame.
- Animating layout-heavy CSS properties.
- Ignoring reduced motion preferences.
- Creating multiple unnecessary animation loops.
requestAnimationFrame vs CSS Animations vs Web Animations API
| Feature | requestAnimationFrame | CSS Animations | Web Animations API |
| Control Level | Full JavaScript control. | Style-based control. | JavaScript control over animation objects. |
| Best For | Games, canvas, custom logic. | Simple UI transitions. | Programmatic UI animations. |
| Performance | Depends on code quality. | Often optimized by browser. | Browser-optimized animation engine. |
| Needs Manual Loop | Yes. | No. | No. |
| Good for Canvas | Yes. | No. | No. |
Key Takeaways
requestAnimationFrame() schedules animation before the next repaint. - It is better than timers for visual animation.
- Use the timestamp argument for frame-rate-independent movement.
- Use
cancelAnimationFrame() to stop scheduled frames. - Keep each animation frame lightweight for smooth performance.
- Respect reduced motion preferences for accessibility.
Pro Tip
Use requestAnimationFrame() when JavaScript must control each
frame, such as canvas games, physics, or custom scroll effects. For simple
button hover effects, fades, and transitions, CSS animations or the Web
Animations API are usually cleaner and easier to maintain.