「アニメーション=重い」は誤解、原因は使い方にある
サイトにふわっとした動きを足しただけでスクロールがカクつくようになった——そんな経験はありませんか。多くの場合、原因は「アニメーションそのもの」ではなく「アニメーションのさせ方」にあります。ブラウザは1秒間に60回(60fps)画面を描き直そうとしていて、1コマあたり使える時間はわずか約16ミリ秒。この時間内に処理が終わらないと、動きがカクつく「フレーム落ち」が起こります。
ここでは、検索でよく聞かれる「サイト 重い アニメーション 対策」というテーマに沿って、初心者の方でもすぐ実践できる7つのコツを具体的に紹介します。
コツ1:動かすプロパティは transform と opacity に絞る
CSSプロパティにはブラウザ内部での処理コストに大きな差があります。widthやheight、top、left、marginなどを変化させると、ブラウザはページ全体の要素配置を再計算する「レイアウト(リフロー)」処理を行い、さらに「ペイント」も発生します。これが重さの最大の原因です。
一方、transformとopacityはレイアウトやペイントを経由せず、GPU上の合成(コンポジット)だけで完結できるため圧倒的に軽量です。
/* 重くなりやすい書き方 */
.box {
transition: left 0.3s, width 0.3s;
}
/* 軽量な書き方 */
.box {
transition: transform 0.3s, opacity 0.3s;
}
.box.active {
transform: translateX(20px) scale(1.05);
opacity: 1;
}
「左に動かしたい」ならleftではなくtranslateX、「大きくしたい」ならwidthではなくscaleに置き換えるだけで体感速度がかなり変わります。まずは自分のCSSでleft・top・width・height・marginをアニメーションさせている箇所がないか見直してみましょう。
コツ2:will-change は「ここぞ」の場面だけ使う
will-change: transform;をつけると、ブラウザに「このプロパティは今後変化しますよ」と事前に伝えることができ、専用のレイヤーを準備してくれるため動き出しが滑らかになります。
.card:hover {
will-change: transform;
}
ただし便利だからといって全要素にwill-changeをつけるのは逆効果です。レイヤーはメモリを消費するため、多用するとかえってメモリ不足で重くなります。目安として「常時ではなくホバーやアニメーション直前だけ付与する」「アニメーションが終わったらwill-change: autoに戻す」の2点を守りましょう。JavaScriptでアニメーション開始時に付与し、transitionendイベントで解除する方法もおすすめです。
コツ3:同時に動く要素の数を絞る
1画面内で同時に10個も20個も要素が動いていると、それぞれが軽くてもトータルの処理量は積み重なります。特にスクロール連動のフェードインなどは「見えている範囲だけ」動かすのが鉄則です。次に紹介するIntersectionObserverと組み合わせることで、画面外の要素は動かさない設計にできます。
コツ4:IntersectionObserverでアニメーションを間引く
スクロールイベント(scroll)を使って要素の表示位置を毎フレーム計算する実装は、頻繁に発火するため負荷が高くなりがちです。代わりにIntersectionObserverを使うと、要素が画面内に入った瞬間だけ処理が走るため無駄がありません。
const targets = document.querySelectorAll('.fade-in');
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add('is-visible');
observer.unobserve(entry.target); // 一度動いたら監視をやめる
}
});
}, { threshold: 0.2 });
targets.forEach((el) => observer.observe(el));
ポイントはobserver.unobserve()で監視を解除すること。一度表示された要素を何度も監視し続けるのはリソースの無駄です。またモバイル端末ではthresholdを低め(0.1〜0.2程度)にすると、動きが遅れて見える違和感を防げます。
コツ5:ローディング表現は「軽い演出」で妥協しない
読み込み待ちの時間を埋めるローディング表現も、実装によっては重くなりがちなパーツです。派手なJavaScriptアニメーションよりも、CSSのグラデーションをbackground-positionではなくtransformでスライドさせるだけのシンプルなシマー演出のほうが処理コストは低く済みます。
コツ6:アニメーションの数より「見せ方」で差をつける
初心者ほど「動きの種類を増やす」ことに意識が向きがちですが、実際にユーザーの印象を左右するのはタイミングと間(ま)です。すべての要素に同じ速度・同じ動きをつけるより、transition-delayを50〜100ミリ秒ずつずらして順番に表示させるほうが、少ない処理量でリッチな印象を与えられます。
.item:nth-child(1) { transition-delay: 0ms; }
.item:nth-child(2) { transition-delay: 80ms; }
.item:nth-child(3) { transition-delay: 160ms; }
数を減らしてクオリティを上げる、という発想がパフォーマンスと見た目の両立には欠かせません。
コツ7:prefers-reduced-motion に配慮する
意外と見落とされがちですが、OSの設定で「視差効果を減らす」をオンにしているユーザーには、過度なアニメーションが負担になることがあります。CSSのメディアクエリで簡単に対応できるので、必ず入れておきましょう。
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.001ms !important;
transition-duration: 0.001ms !important;
}
}
これは処理負荷そのものを下げる対策ではありませんが、「重く感じさせない」という体感速度の観点では非常に効果的な一手です。
まとめ
サイトを重くしないアニメーション設計のコツは、特別な技術より「基本を丁寧に守ること」に尽きます。
- 動かすのは原則 transform と opacity だけ
- will-change は使う場面を絞り、終わったら解除
- 同時に動く要素の数を絞る
- スクロール監視は IntersectionObserver で間引く
- ローディング表現もシンプルな実装を選ぶ
- 動きの数より間(ディレイ)で魅せる
- prefers-reduced-motion を忘れずに
この7つを意識するだけで、見た目のリッチさを保ちながら軽快に動くサイトに近づけます。動くWebパーツを選ぶ際も、こうした軽量設計がされているかどうかをチェックポイントにしてみてください。