この記事は最終更新日から1年以上経過しています。

CSSのレンダリングの仕組みとGPUアクセラレーションの注意点

公開日:

更新日:

スタッフブログ

こんにちは。田村です。
今回は「CSSアニメーションをより滑らかに動かすポイント」について、レンダリングの仕組みとGPUアクセラレーションの注意点を交えながらまとめてみました。
Webサイトでアニメーションを取り入れる場合、プロパティの選び方やGPUの活用次第でパフォーマンスが大きく変わります。
それでは早速、ブラウザのレンダリング工程から見ていきましょう。

CSSレンダリングの概要

ざっくりレンダリングの流れ

ブラウザは、HTML/CSS/JavaScriptを解析してまず DOMツリー と CSSOMツリー を生成します。
その後、この2つを合体させた Render Tree を作り、以下の手順で画面に描画します。

Rendering(レンダリング)

Layout(レイアウト)
各要素の大きさや位置を計算する工程。一般的に「リフロー」とも呼ばれます。

Painting​(ペインティング)

Paint(ペイント)
テキストや背景色、ボーダー、画像などを ピクセル情報 として実際に塗りつぶす工程。
Composite Layer (コンポジットレイヤー)
レイヤーごとにGPUで合成し、最終的な見た目を描画する工程。

アニメーションを滑らかにする際に重要なのは、GPUアクセラレーションは主にComposite Layerで働くということです。
要素をうまく使うと、レイアウトの再計算(リフロー)を発生させずにCompositeだけでアニメーションできるため、滑らかな動作が期待できます。

GPUアクセラレーションが働く代表的なプロパティ

  • will-changeプロパティの使用
  • transformの3D変換
  • opacityの変更
  • position: fixedの要素

transform

transform: translate(), scale(), rotate(), skew() などは、Layoutに影響しない ため、要素の大きさ・位置、レイアウトの再計算(リフロー)を必要としません。

opacity

opacityの変更は、レイアウト計算(幅や高さの再計算)には影響しないため、通常はLayoutやPaintを変えずにComposite Layerだけで変化を適用できます。
そのため、opacityのフェードアニメーションは比較的スムーズに動作します。

ただし、opacity は背景や重なり合いが複雑な場合paint処理が増える場合もあるので、必ずしも高速とは限りません。

CPUレンダリングとGPUレンダリングの違い

CPU側での処理
top や left, width, height などのプロパティをアニメーションさせると、毎フレームごとにレイアウトの再計算(リフロー)が発生します。
複数要素で同時にこうしたアニメーションを使うとCPUに大きな負担がかかり、カクつきの原因になります。

GPU側での処理
GPUは 2D/3Dの描画や合成 に特化しており、並列処理が得意です。
transform や opacity でアニメーションする場合は、新たなレイアウト計算をせずにComposite Layerのみで見た目を更新できるため、フレームレート(60fps)を維持しやすいというメリットがあります。


任意でGPUアクセラレーションを引き出す方法

will-changeプロパティ
ブラウザに「もうすぐこのプロパティが変化するぞ」と知らせることができるので、あらかじめ最適化しておいてくれます。
ですが、ブラウザはすでに可能な限りすべての最適化を試みていますので指定しすぎると不要なレイヤーが生成されるため、使用には注意が必要です。

.element {
  will-change: transform, opacity;
}

GPU処理に良いケース

複数要素を同時にアニメーションさせる場合
画像ギャラリーが横に大量に流れるサイトなどは、レイアウトの再計算(リフロー)を最小限に抑え、滑らかな移動がしやすい。

スクロール連動やドラッグ移動など、ユーザー操作が頻繁に行われるUI
リアルタイムで要素位置が変化する場合に効果を発揮しやすい。

端末の性能が低い、またはFPSを確保したい場面
スマートフォンやタブレットなどCPUリソースが限られる環境で、GPUをフル活用することでカクつきを低減できる。

GPU処理の注意点

レイヤーが増えすぎた場合
レイヤーが増えすぎるとGPUのメモリ消費が増大し、合成コストもかさんで逆効果になる場合がある。

レイアウト変更時
transform や opacity はあくまで見た目を変えるプロパティなので、要素の実際の位置・高さを変えたい場合はレイアウトの再計算(リフロー)が発生する。

ブラウザ依存
古い端末や特定ブラウザではGPUの最適化が効きにくい。

メインスレッドの負荷は別問題
JavaScriptが重い処理を実行していれば、アニメーションの更新タイミング自体が遅れ、カクつきが発生することもある。

実測・検証方法

最終的には実際に パフォーマンス計測 してみることが大切です。

Chrome DevToolsのレンダリングを活用する


まとめ

transform や opacity を中心にアニメーションを組み立て、なるべくレイアウトの再計算(リフロー)を防ぎ、GPUアクセラレーションを効かせるのが、CSSアニメーションを滑らかに動かすポイントです。
やみくもにwill-changeを使うとレイヤーが乱立し、逆効果になることもありますので、Chrome DevToolsで実際に計測し、Paint/Compositeをチェックしながら、GPU処理が必要な箇所に使用すると良いでしょう。
より滑らかなアニメーションを実装してみてください!

告知


2025年1月31日(金)21:00~29:00 開催の「#朝までマークアップ 2(CSS編)」に出演いたします。
当日は、CSS アニメーションに関するお話をします。この記事にご興味を持っていただけましたら、ぜひご参加ください!


この記事をシェアする

関連記事

この記事のハッシュタグ #CSS #アニメーション から関連する記事を表示しています。

CSSでコマ送りのように動きを切り替えるアニメーション

こんにちは。田村です。 CSSアニメーションで、コマ送りのような「カクカク」と動きを切り替えるアニメーションを作りたい場合がありました。 そんなときはsteps() 関数を使うと実現可能です。 steps() とは? steps() は、CSSアニメーションの animation-timing-function プロパティで使われる関数の一つです。 通常のアニメーションが滑らかに動くのに対し、steps() を使うと 「段階的に進むアニメーション」 を作ることができます。 どんな場面で使えるのか? スプライトアニメーション 1枚の画像に複数のフレームを描き、steps() を使って特定のフレームごとに切り替えることができます。 コマ送りアニメーション 動画を再現するようなアニメーションをCSSで実現できます。 進行状況を表現 プログレスバーなど進行状況の表示に使用できます。 基本的な使い方 steps() 関数には、2つの主要な引数があります。 steps(段階数, タイミング) 段階数 アニメーションを何段階に分割するかを指定します。 steps(4) → 4段階の動き タイミング jump-none 0%と100%の状態を表示して間は均等に埋める jump-start / start コマの最初に動くので開始時0%の状態は見えない jump-end /end コマの最後に動くので終了時100%の状態が見えない jump-both startとendの動きをして間を埋めるので0%と100%の状態が見えない .element { /*アニメーションを4段階に分けて、各ステップが終了後に切り替わる。*/ animation: example 4s steps(4, end) infinite; } @keyframes example { from { background-position: 0 0; } to { background-position: -400px 0; } } まとめ steps()関数は段階的な動きが必要なアニメーションに利用できます。 また、start と end の使い分けで、タイミングを調整できます。 スプライトアニメーションやプログレスバー、コマ送りなど、幅広い用途に活用可能ですのでぜひ試してみてださい!

スタッフブログ

ユーザーの設定をCSSアニメーションに反映させる

こんにちは。田村です。 CSSアニメーションはリッチな動きが表現でき便利ですがユーザーによってはアニメーションをオフにしたいということがあります。 OS側で「動きをへらす」という設定があり、これをCSS側で判断したい場合はありました。 prefers-reduced-motion とは? prefers-reduced-motion は、ユーザーのOSやブラウザの設定に基づいて、動きの多いアニメーションやエフェクトを制御するためのCSSメディアクエリです。 OSの設定で「動きを減らす」という設定が提供されており、この設定が有効になっているユーザーに対し、アニメーションを軽減するスタイルを適用できます。 次のように読むそうです。 prefers-reduced-motion(プリファーズ・リデュースド・モーション) prefers(プリファーズ):好む reduced(リデュースド):減少した motion(モーション):動き どんな場面で使えるのか? 動きが苦手なユーザーへの配慮 激しいアニメーションや過剰な動きを好まないユーザーに快適なユーザー体験を提供できます。 アクセシビリティ向上 WCAGの達成基準にも含まれています。 「達成基準 2.3.3: インタラクションによるアニメーションを理解する」 基本的な使い方 prefers-reduced-motion は、CSSのメディアクエリとして以下のように使います。 /* 通常時のスタイル */ .animated-box { animation: bounce 2s infinite; } /* 動きを抑える設定の場合 */ @media (prefers-reduced-motion: reduce) { .animated-box { animation: none; } } まとめ prefers-reduced-motion は、ユーザーが動きを減らす設定をしている場合に、アニメーションを無効化または軽減できるCSSメディアクエリです。 動きに敏感なユーザーにも優しい動きを提供し、アクセシビリティを向上することができます。

スタッフブログ