Web制作

CSSアニメーションを多用するとパフォーマンスが落ちるのか?

CSSアニメーションを多用するとパフォーマンスが落ちるのか?

キーフレームを足すたびに、ページが豪華に見える。スクロールのたびに数十個が同時に動く。見た目の話と、描画の話は別です。CSSアニメーションを多用するとパフォーマンスは必ず落ちる、という公式の一文はありません。落ちやすい条件は、プロパティの種類と、同時に動く量と、メインスレッドの忙しさです。

結論です。合成(コンポジタ)向きの transform と opacity に閉じ、動かす要素を絞ると、落ち方は抑えやすい。web.dev のアニメーション案内 も、レイアウトやペイントを起こすプロパティより、合成だけの変化を勧めています。保証ではありません。端末、他のJS、画像量で結果は変わります。測る前提です。

この記事では、フリーランスのWebディレクター兼エンジニアとして、「多用」が負荷になる経路と、現場で切る線を整理します。架空の FPS 改善%は出しません。動きの要否(演出か、状態の伝達か)は、別稿のモーション整理に寄せ、ここでは描画側に限ります。

ブラウザが毎回やっていること

1フレームのあいだに、スタイル計算、レイアウト、ペイント、合成が並びます。説明は MDN のレンダリング概要 と、上記の web.dev が詳しいです。

  • top / left / width / margin をアニメーションする → レイアウトが走りやすい
  • box-shadow や大きな blur を毎フレーム変える → ペイントが重くなりやすい
  • transform と opacity に閉じる → 合成側で済むことが多い

「CSSだからJSより常に軽い」は成り立ちません。CSSも、レイアウトを揺らせば高いです。JSの requestAnimationFrame も、同じプロパティを変えれば同じ種類の仕事です。言語の優劣ではなく、何を、何個、何秒動かすかです。

悪い実装と、負荷を抑えやすい実装

悪い実装

.card {
  position: relative;
  animation: float 1.2s ease-in-out infinite;
}

@keyframes float {
  0%,
  100% {
    top: 0;
    box-shadow: 0 8px 32px rgb(0 0 0 / 0.35);
  }
  50% {
    top: 16px;
    box-shadow: 0 24px 64px rgb(0 0 0 / 0.45);
  }
}

一覧に20枚あると、位置と影が同時に変わります。レイアウトとペイントが続きやすい形です。必ずジャンク、とは言いません。低スペックとバックグラウンドのタブでは、起きやすくなります。

負荷を抑えやすい実装

@media (prefers-reduced-motion: no-preference) {
  .card {
    animation: float 1.2s ease-in-out infinite;
  }
}

@keyframes float {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-8px);
  }
}

移動は translate に閉じます。影を毎フレーム動かさない。動きを消したい人向けに、prefers-reduced-motion を見る。OSの設定を無視して動かし続けるのは、負荷の話以前に、操作の負担です。

「多用」が効いてくる3つの経路

1. 同時に動く要素の数

ヒーロー1枚のフェードと、グリッド20枚の無限ループは、仕事量が違います。交差してから一度だけ動かす、一度動かしたら止める(animation-iteration-count: 1 や、JSなら unobserve)と、常時ループより仕事は減りやすい。減る量はページ次第です。

2. スクロールと同時に走る

スクロール中は、すでに合成とヒットテストが忙しい。INP はクリックやキーが対象で、スクロールそのものの指標ではありません。それでも、スクロールハンドラでスタイルを大量に変えると、次の操作の遅れにつながることがあります。CSSの animation だけが原因、と決めません。交差判定のJSとセットで見ます。

3. will-change の付けっぱなし

MDN の will-change は、使いすぎるとメモリを食う、と注意しています。動かす直前に付け、終わったら外す、が文書の趣旨です。全カードに常時 will-change: transform は、層を増やす側に振れます。速くなる保証ではありません。

実務で切る線

カンプレビューで聞くこと

「この動きは、状態が変わったと伝えるためか、飾りか」。飾りなら、同時に何個動かすかを先に決める。全部に同じイージングを配る前に、ファーストビューだけ、に絞れることが多い。

実装で見るもの

  • アニメ対象は transform / opacity か
  • infinite がビューポート外でも起きていないか
  • 大きな画像や動画と、同じ区間で重なっていないか

ラボの計測は、Chrome の Performance パネルと、アニメーションの検査 で足ります。フィールドの体感は、端末を分けて見る。Lighthouse の点数だけを成果にしない。

AIにキーフレームを頼むとき

「全部 transform と opacity にする」「一覧ではループしない」を先に書く。生成結果に top や margin が混ざっていないかを人が見る。プロンプトを構造化するのは、指示の再現用です。モデルが速くなる、という意味ではありません。

現場でハマりやすい点

  • filter: blur() をスクロール連動で変える: ペイントが続きやすい、という報告は多い。必ず落ちる、とは書きません。外して差を見る。
  • SVG の path を細かくアニメーションする: 要素数と計算が増えます。アイコン1つと、背景一面では話が違います。
  • transition: all: 想定外のプロパティまで補間します。対象を列挙する。
  • 演出用ライブラリのデフォルト: 便利な初期値が、レイアウトプロパティのことがあります。初期設定を読む。

参考にする一次情報は、web.dev のアニメーション案内と、MDN の CSS / will-change / prefers-reduced-motion です。

まとめ:多用そのものより、何を何個動かすか

CSSアニメーションが多いと遅くなる、とだけ覚えると、必要なホバーまで切ります。落ちやすいのは、レイアウトを揺らすプロパティと、同時に動く量と、スクロールやJSとの重なりです。合成に閉じ、数を決め、動きを止められるようにする。その順が、現場の確認です。

動きの量と描画の切り方、既存演出の削り方の相談は、相談・お問い合わせからどうぞ。