requestAnimationFrame は「ブラウザに最適なタイミングでアニメを進めてもらう仕組み」
requestAnimationFrame(略して rAF)は、
「アニメーションを滑らかに動かすための、ブラウザ専用のタイマー」 です。
setInterval や setTimeout でもアニメは作れますが、
それらは「一定間隔で実行するだけ」で、ブラウザの描画タイミングとは無関係です。
一方、requestAnimationFrame は
ブラウザが画面を描画する直前に呼ばれる
1 秒間に最大 60 回(60fps)で実行される
タブが非表示のときは自動で止まる(無駄な処理をしない)
という特徴があり、
アニメーションを作るなら最優先で使うべき API です。
setInterval と requestAnimationFrame の違いをまず掴む
setInterval は「時間ベース」、rAF は「描画ベース」
setInterval
「◯ミリ秒ごとに実行」
ブラウザの描画タイミングとは無関係
処理が重いとカクつく
requestAnimationFrame
「次の描画タイミングで実行」
ブラウザが最適なタイミングで呼んでくれる
滑らかで省エネ
つまり、
アニメーションは「描画のタイミングに合わせる」ほうが圧倒的に自然 です。
これが rAF がアニメーションに向いている理由です。
requestAnimationFrame の基本形
一番シンプルな書き方
function update() {
console.log("描画タイミングで呼ばれた");
requestAnimationFrame(update);
}
requestAnimationFrame(update);
JavaScriptポイントは、
requestAnimationFrame(update) を呼ぶと
→ 次の描画タイミングで update が呼ばれる
→ その中でまた requestAnimationFrame(update) を呼ぶ
という「自分で自分を呼び続ける」スタイルです。
これがアニメーションの基本パターンになります。
コールバックには「経過時間」が渡される
rAF のコールバックは、
「今の時刻(ミリ秒)」 を引数として受け取れます。
function update(time) {
console.log(time); // 0 から始まり、ミリ秒で増えていく
requestAnimationFrame(update);
}
requestAnimationFrame(update);
JavaScriptこの time を使うと、
「時間に応じて位置を変える」などのアニメーションが作りやすくなります。
具体例:四角を右に動かすアニメーション
HTML
<div id="box"></div>
<style>
#box {
width: 50px;
height: 50px;
background: red;
position: absolute;
left: 0;
top: 50px;
}
</style>
JavaScript
const box = document.querySelector("#box");
let start = null;
function animate(time) {
if (!start) start = time;
const progress = time - start; // 経過時間(ミリ秒)
const x = progress / 5; // 5ms で 1px 動く
box.style.left = `${x}px`;
if (x < 300) {
requestAnimationFrame(animate); // まだ動かす
}
}
requestAnimationFrame(animate);
JavaScriptここで起きていることは、
アニメ開始時の時刻を記録
経過時間に応じて位置を計算
300px まで動いたら終了
という流れです。
setInterval でやるよりも、
動きが滑らかで、ブラウザの負荷も少ない のが分かります。
requestAnimationFrame の「止め方」
rAF は ID を返す → cancelAnimationFrame で止める
requestAnimationFrame も、setTimeout や setInterval と同じく「ID」を返します。
const id = requestAnimationFrame(animate);
cancelAnimationFrame(id);
JavaScriptただし、アニメーションでは
「コールバックの中で次の rAF を呼ぶ」ことが多いので、
止めるときは「次の rAF を呼ばない」ようにするのが一般的です。
例えば、
let running = true;
function animate() {
if (!running) return;
// アニメ処理
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
// どこかで停止
running = false;
JavaScriptというように、
フラグで制御する のがよくあるパターンです。
requestAnimationFrame が優れている理由を深掘りする
ブラウザの描画タイミングに同期する
ブラウザは通常、
1 秒間に 60 回(60fps)画面を描画します。
rAF はこの描画の直前に呼ばれるため、
画面の更新と処理がズレない
無駄な再描画が起きない
カクつきが少ない
というメリットがあります。
タブが非表示のときは自動で止まる
setInterval はタブが非表示でも動き続けますが、
rAF は 非表示のときは自動で停止 します。
これにより、
CPU の無駄遣いを防ぐ
バッテリー消費を抑える
という効果があります。
アニメーションを作るなら、
この「自動で止まる」性質は非常にありがたいです。
setInterval の「ズレ問題」が起きない
setInterval は処理が重いと、
本来 16ms ごとに動くはずが
20ms、30ms とズレていく
という問題があります。
rAF は「描画タイミングに合わせる」ので、
ズレが蓄積しにくく、
常に滑らかさを保ちやすい のが特徴です。
具体例:フェードインアニメーション
HTML
<div id="box">Hello</div>
<style>
#box {
opacity: 0;
transition: none;
}
</style>
JavaScript
const box = document.querySelector("#box");
let start = null;
function fade(time) {
if (!start) start = time;
const progress = (time - start) / 1000; // 1秒でフェードイン
box.style.opacity = Math.min(progress, 1);
if (progress < 1) {
requestAnimationFrame(fade);
}
}
requestAnimationFrame(fade);
JavaScriptCSS の transition を使わず、
rAF だけでフェードインを作る例 です。
時間ベースで計算しているので、
PC の性能に関係なく「1 秒でフェードイン」が実現できます。
初心者として requestAnimationFrame で本当に掴んでほしいこと
requestAnimationFrame は「アニメーション専用のタイマー」
ブラウザの描画タイミングに合わせて呼ばれるので滑らか
タブが非表示のときは自動で止まる(省エネ)
コールバックの中で次の rAF を呼ぶのが基本パターン
時間(time 引数)を使うと、正確なアニメーションが作れる
止めるときは cancelAnimationFrame か、フラグ管理が一般的
まずは、
四角を動かす
フェードインさせる
回転させる
などの小さなアニメーションを作ってみると、
「ブラウザと仲良く動くアニメーション」の感覚がすぐに掴めます。
次のステップとして、
Canvas やゲームループに挑戦すると、
rAF の真価がさらに見えてきます。
