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との重なりです。合成に閉じ、数を決め、動きを止められるようにする。その順が、現場の確認です。
動きの量と描画の切り方、既存演出の削り方の相談は、相談・お問い合わせからどうぞ。