PERFORMANCE

Core Web Vitals に影響しないアニメーション設計

Webアニメーションを実装する際、Core Web Vitals(LCP・CLS・INP)を悪化させないことが極めて重要です。SEO評価にも直結するこれらの指標を保ったまま、滑らかな動きを実装する技術を解説します。

LCP(Largest Contentful Paint)を守る

問題: ヒーロー画像にフェードイン演出を入れると、画像が表示されるタイミングが遅れて LCP が悪化する。

対策1: メインコンテンツの初期表示は static で、装飾アニメーションのみ後から追加する。

対策2: <link rel="preload" as="image" href="hero.jpg"> で重要画像を先読み。

対策3: Above the fold のアニメーションは LCP発火後(DOMContentLoaded + 100ms)に開始する。

CLS(Cumulative Layout Shift)を守る

問題: アニメーションで要素のサイズが変わると、周囲の要素が動いて CLS が増加する。

対策: transformopacity だけを動かす(これらは GPU レイヤーで処理され、レイアウトに影響しない)。

NG例: width: 100px → 200px のアニメーション → 周囲が押し出される。

OK例: transform: scaleX(1) → scaleX(2) → 視覚的には同じだがレイアウトは変わらない。

INP(Interaction to Next Paint)を守る

問題: クリック直後に重い JavaScript 処理が走ると、アニメーション開始が遅れる。

対策: クリックハンドラ内で重い処理は requestIdleCallback に逃がす。

対策: アニメーション開始は同期的に、データ処理は非同期に切り分ける。

目標: クリックから200ms以内に視覚反応を返す。

GPU レイヤー昇格テクニック

will-change: transform — ブラウザに事前に GPU レイヤーを準備させる。

transform: translateZ(0) — レガシーな GPU 昇格テクニック。今は will-change を推奨。

乱用禁止 — 全要素に will-change を付けるとメモリ消費が爆発する。必要な要素にだけ。

アニメーション終了後は外すelement.style.willChange = 'auto'; でクリーンアップ。

60fps を保つチェックリスト

✅ transform / opacity のみを動かしているか

✅ ボックスシャドウのアニメーションを避けているか(重い)

filter: blur() 等の重いCSSプロパティを動かしていないか

✅ JavaScript アニメーションは requestAnimationFrame を使っているか

✅ Chrome DevTools の Performance タブで「Long Frames」を確認したか

FAQ

box-shadow のアニメーションは重い?
はい、box-shadow のサイズや色のアニメーションは GPU 最適化が効きにくく重いです。代替として要素を重ねるテクニックがあります。
filter: blur() のアニメーションは?
極めて重いです。アニメーションに使うのは避け、静的にのみ使用してください。
Mobile での 60fps 達成は難しい?
transform/opacity のみに絞れば、廉価な Android でも 60fps を達成できます。
Core Web Vitals の計測ツールは?
PageSpeed Insights(無料)と Chrome DevTools の Lighthouse タブが基本。実ユーザー指標は Google Search Console で確認できます。