こんにちは!フロントエンドの現場を渡り歩いているチーフアーキテクトの私です。
Web制作やJavaScriptの勉強を少し進めると、「画面を滑らかに動かしたいなら `requestAnimationFrame` を使おうね」という話に必ず出会うと思います。でも、最初にこの長い名前を見たとき、「なんだこれ、呪文か?」って思いませんでしたか? 大丈夫です、最初はみんなそう思います。
今日は、この `requestAnimationFrame`(通称:rAF)が、Webブラウザの中でどんな風に働いているのか、そしてなぜ私たちがこれを使うと画面がスルスルと気持ちよく動くようになるのかを、身近な例えを交えながらじっくりとお話ししていきますね。
—
1. Webブラウザの「お仕事カレンダー」を覗いてみよう
まずは、Webブラウザが画面を表示する仕組みを、私たちの日常にたとえてみましょう。
想像してみてください。あなたは、ものすごく手際の良い「超特急の看板職人」です。お客さんから「この看板の文字を書き換えて!」と次々にお願いが来ます。
もし、お客さんが来るたびに、その場でペンキを塗っては乾かし、塗っては乾かし……としていたら、どうでしょう? ペンキが乾く前に対象が動かされたりして、ぐちゃぐちゃになってしまいますよね。
そこで、この職人さん(ブラウザ)は、「1秒間にだいたい60回(約16.7ミリ秒に1回)、決まったタイミングでまとめて看板をペンキ塗りするぞ!」という自分ルール(スケジュール)を持っています。これが、いわゆるブラウザのレンダリングループ(更新サイクル)です。
ブラウザの内部では、この1回分のサイクルの中で、以下のようなお仕事をきっちり順番にこなしています。
1. JavaScriptの実行:データを計算したり、イベントを処理したりするよ。
2. スタイルの計算(Style):CSSがどう当たっているか再計算するよ。
3. レイアウト(Layout):要素の大きさや位置をピクセル単位で決めるよ(昔はリフローって呼んでたね)。
4. ペイント(Paint):色を塗ったり文字を描いたりするよ。
5. 合成(Composite):レイヤーを重ね合わせて、画面に出力するよ!
この「1秒間に60回」の電車が発車するタイミングに、自分のアニメーション処理をピタッと正確に乗り込ませるための切符、それが `requestAnimationFrame` なんです。
—
2. なぜ `setTimeout` じゃダメなの?
「アニメーションなら、`setInterval` や `setTimeout` で 16ミリ秒(1000ms ÷ 60 ≒ 16.6ms)ごとに動かせばいいんじゃないの?」と思ったそこのあなた、非常に鋭い着眼点です!
しかし、ここに大きな落とし穴があります。
`setTimeout` は、いわば「マイペースな目覚まし時計」です。ブラウザの心の準備(今のレンダリングサイクルがどこかなんてお構いなし)を無視して、「おい、時間だぞ!」と無理やりJavaScriptを割り込ませます。
その結果、何が起きるか?
ブラウザがちょうど「レイアウトやペイントの計算で大忙し!」という絶妙なタイミングで `setTimeout` が発動してしまうと、ブラウザは「うわ、今の計算やり直しじゃん……!」と、無理やり二度手間を強いられます。これが、画面がカクついたり、ファンが唸りを上げたりする原因(フレームドロップ)なんです。
その点、`requestAnimationFrame` は、ブラウザの運行管理者とガッチリ握手しています。
「ブラウザさん、次にキャンバスを綺麗に塗り直すタイミングが来たら、私に一声かけて!その直前にアニメーションの計算をするからさ!」 と、お互いの息を完璧に合わせて動くことができるのです。だから、ものすごく滑らかなんです。
—
3. `requestAnimationFrame` の基本的な使い方
百聞は一見にしかず、実際にコードを見てみましょう。
今回は、画面の中でボックスがスルスルと右に移動していく、一番シンプルなサンプルを用意しました。エディタにコピーしてブラウザで開けば、その滑らかさを体感できますよ。
このコードのミソは、関数の中で自分自身をもう一度 `requestAnimationFrame` で予約し直しているところです。
「次の電車に乗るために、到着したらまた次の切符を買う」というループを無限に繰り返すことで、パラパラマンガのように滑らかな動きを生み出しているわけですね。
—
4. 現場のプロからのちょっとしたアドバイス(つまずきポイント)
最後に、実務で `requestAnimationFrame` を扱うときによくある「あれ?」というポイントをシェアしておきますね。
- タブを切り替えると、自動で省エネモードになるよ
`setInterval` と違って、ユーザーが別のタブに移動したり、ブラウザを最小化したりすると、`requestAnimationFrame` は自動的に実行を一時停止してくれます。CPUやバッテリーを無駄に消耗させない、ブラウザの優しい親切設計です。「裏画面に行ったのにアニメーションが動き続けてパソコンのファンが爆音で回り出した……」なんて心配はもういりません。
- 時間は引数(Timestamp)から受け取ろう
先ほどのサンプルではシンプルにするために `currentPosition += 2` と固定値で進めましたが、実は `requestAnimationFrame` は実行された瞬間の正確な時間(ミリ秒)をコールバック関数の引数としてこっそり教えてくれます。「前回のフレームから何ミリ秒経過したか」を計算に使うと、どんな高性能なPCでも低性能なスマホでも、アニメーションのスピードが同じになる(環境依存しなくなる)プロ仕様のコードが書けるようになりますよ。
—
いかがでしたでしょうか?
`requestAnimationFrame` は、ブラウザのレンダリングの仕組みと仲良くなるための最高の相棒です。難しく考えず、「ブラウザのお仕事カレンダーに、自分の予定を優しく書き込むための便利ツールなんだな」と捉えてもらえれば大成功です。
あなたのWeb制作ライフが、カクつきのない滑らかで心地よいものになりますように。それではまた、次の現場でお会いしましょう!

コメント