CSS transitionsが引き起こすLayout Shift

Layout Shiftを引き起こすCSS transitionsを見つけて修正する方法を学ぶ

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-03-27

なぜCSS transitionsがレイアウトシフトを引き起こすのか

CSS transitionsによって引き起こされるCumulative Layout Shiftsは、多くの場合、ページの読み込みフェーズの初期段階で発生します。これらのレイアウトシフトは一貫して発生するわけではないため、デバッグが困難です。

最終レビュー: 2026年3月 Arjen Karel

transition: all の問題

transitionに関連するレイアウトシフトの最も一般的な原因は transition: all です。2022年 Web AlmanacのCSSに関する章によると、53%のページが transition: all を使用しています。これは、width、height、margin、paddingなどのレイアウトに影響を与えるものを含め、すべてのプロパティの変更がアニメーション化されることを意味します。

CSS transitionには、property、duration、timing-function、delayがあります。省略形は次のようになります:

/* property | duration | timing-function | delay */
transition: margin-right 4s ease-in-out 1s;

問題は、開発者がアニメーション化したい正確なプロパティを指定する代わりに、transition: all .3s ease と記述したときに始まります。ページの読み込み中、ナビゲーションメニューなどのファーストビューの要素は、初期状態(スタイルなし)から最終状態(スタイル適用済み、または非表示)へと遷移します。transitionのプロパティが all の場合、これには width、height、さらには visibility も含まれます。その結果、読み込み中にのみ発生し、一貫して再現することがほぼ不可能なレイアウトシフトが発生します。

どのCSSプロパティがレイアウトシフトを引き起こすのか?

すべてのCSS transitionsがレイアウトシフトを引き起こすわけではありません。要素のジオメトリや位置を変更するプロパティのみが、ブラウザのレイアウトステップをトリガーします。Googleの調査によると、レイアウトを誘発するCSSプロパティをアニメーション化しているページは、CLSの基準を満たす可能性が15%低くなります。marginborder-width をアニメーション化しているページは、ほぼ2倍の割合でCLSが不良(poor)になります。

レイアウトシフトを引き起こすプロパティ: width, height, margin, padding, top, left, right, bottom, border-width, font-size, display

安全なプロパティ (コンポジットのみ、レイアウトシフトなし): transform, opacity, filter, clip-path

安全なプロパティ (ペイントのみ、レイアウトシフトなし): background-color, color, box-shadow, outline

重要なポイント: transformopacity は完全にブラウザのコンポジタースレッドによって処理されます。これらがレイアウトの再計算をトリガーすることは決してないため、CLSにカウントされることはありません。要素を移動する必要がある場合は、top/left の代わりに transform: translate() を使用します。視覚的にサイズを変更する必要がある場合は、width/height の代わりに transform: scale() を使用します。

以下の例をご覧ください。これは、ページの読み込みフェーズ中に発生するCSS transitionsによって引き起こされたレイアウトシフトを示しています。このパターンは頻繁に見られますが、この種の問題を見つけて修正するのは困難な場合があります。

CSS transitionsを見つけて修正する

CSS transitionsによって引き起こされるすべてのレイアウトシフトを見つけて修正するには、簡単なテストを実行する必要があります。まず、ページ上のすべてのCSS transitionsを見つけます。次に、それらのいずれかがレイアウトに影響を与えるプロパティを変更しているかどうかを確認します。最後に、それらのtransitionsを無効化または変更した場合の影響を測定し、それらがCLSを引き起こしていたことを確認します。

Core Web Vitalsのヒント: CSS transitionsによって引き起こされるCumulative Layout Shiftsは、多くの場合、ページの読み込みフェーズの初期段階で発生します。これらのレイアウトシフトは一貫して発生するわけではないため、デバッグが困難です。モバイルデバイスをエミュレートしてネットワークを遅くし、キャッシュを無効にすることで、それらを見つけやすくなります!

ステップ 1: CSS transitionsを見つける

CSS transitionsの検索は手動で行うことができます。すべてのスタイルシートを調べ、「transition」という単語を検索します。これは10分以内で終わる作業のはずですが、もっと良い方法があります!以下のスニペットをコンソールに貼り付けてEnterキーを押すだけです。

(() => {

  let nodeTable = [];
  let nodeArray = [];

  // Get the name of the node
  function getName(node) {
    const name = node.nodeName;
    return node.nodeType === 1
      ? name.toLowerCase()
      : name.toUpperCase().replace(/^#/, '');
  }

  // Get the selector
  const getSelector = (node) => {
    let sel = '';

    try {
      while (node && node.nodeType !== 9) {
        const el = node;
        const part = el.id
          ? '#' + el.id
          : getName(el) +
          (el.classList &&
            el.classList.value &&
            el.classList.value.trim() &&
            el.classList.value.trim().length
            ? '.' + el.classList.value.trim().replace(/\s+/g, '.')
            : '');
        if (sel.length + part.length > (100) - 1) return sel || part;
        sel = sel ? part + '>' + sel : part;
        if (el.id) break;
        node = el.parentNode;
      }
    } catch (err) {
      // Do nothing...
    }
    return sel;
  };

  const getNodesWithTransition = (node) => {

    // Get the computed style
    let cs = window.getComputedStyle(node);
    let tp = cs['transition-property'];
    let td = cs['transition-duration'];

    // If there is a transition, add it to the table
    if (tp !== '' && tp !== 'none' && td != '0s') {
      nodeTable.push({ selector: getSelector(node), transition: cs['transition'] });
      nodeArray.push(node);
    }

    // Recursively call this function for each child node
    for (let i = 0; i < node.children.length; i++) {
      getNodesWithTransition(node.children[i]);
    }
  }

  // find all transitions
  getNodesWithTransition(document.body);

  // Display the results in the console
  console.log('%cReadable table of selectors and their transitions', 'color: red; font-weight: bold;');
  console.table(nodeTable);

  console.log('%cNodeList for you to inspect (harder to read but more info)', 'color: red; font-weight: bold;');
  console.log(nodeArray);


  // styles to temporarity override the transitions
  let selectors = nodeTable.map((item) => item.selector).join(', ');

  console.log('%cSpecific CSS to disable all transitions on this page', 'color: red; font-weight: bold;');
  console.log(`<style>${selectors}{transition-property: none !important;}</style>`);

  console.log('%cGlobal CSS to disable all transitions on this page (not suggested on production)', 'color: red; font-weight: bold;');
  console.log(`<style>*{transition-property: none !important;}</style>`);

})()

これにより、すべてのtransitions、それらが機能している要素、およびtransitionsに関する詳細を示す表が表示されます。

レイアウトシフトを見つけるには、widthheightmarginpaddingtopleftdisplay、そして特にallall はすべての有効なtransitionプロパティを含むため)などのtransitionプロパティを探します。

ステップ 2: CSS transitionsを変更する

上記のJavaScriptスニペットは、すべてのtransitionsを表示するだけでなく、それらのtransitionsを無効にする方法のサンプルコードも提供します。簡単なテストの目的であれば、1行のシンプルなCSSコードですべてのtransitionsを無効にするという簡単な方法を取ることをお勧めします。

<style>*{transition-property: none !important;}</style>

もちろん、本番環境ではもう少し工夫が必要です。セレクタごとに不要なtransition-propertiesのみを慎重に削除してください。たとえば、#button{transition: all .2s}#button{transition: background-color .2s} に変更します。

ステップ 3: レイアウトシフトの変化を測定する

次が最後のステップであり、影響を測定します。私のChrome拡張機能であるCore Web Vitals VisualizerやCoreDashのようなRUMツールを使用して、これらのコード変更の実際の影響を測定できます。CoreDashのモニタリングデータでは、transition: all を特定のプロパティに置き換えたサイトは、CLSが平均で40%改善しました。

Transitionのベストプラクティス

  1. 常に正確なプロパティを指定する: transition: all は絶対に使用しないでください。代わりに transition: background-color .2s ease のように記述します。これにより、アニメーション化するつもりのなかったプロパティによる偶発的なレイアウトシフトを防ぐことができます。
  2. アニメーションにはtransformとopacityを使用する: これら2つのプロパティはコンポジターによって処理され、レイアウトをトリガーすることは決してありません。要素を移動するには transform: translate() を、視覚的にサイズを変更するには transform: scale() を、フェードさせるには opacity を使用します。これは、高パフォーマンスなアニメーションのためにGoogleが推奨していることです。
  3. アニメーション化する要素に明示的な寸法を設定する: 要素をtransitionさせる必要がある場合は、transitionの前後に明示的なwidthとheight(またはアスペクト比)があることを確認してください。これにより、周囲のコンテンツがシフトするのを防ぎます。詳細については、自動サイズ調整画像によって引き起こされるレイアウトシフトの修正を参照してください。
  4. will-changeに注意する: CSSの will-change プロパティは、要素を独自のコンポジターレイヤーに昇格させることで、アニメーションの準備をするようブラウザに指示します。しかし、これにはトレードオフがあります。新しいスタッキングコンテキストを作成し、GPUメモリの使用量を増やし、配置された子孫要素の包含ブロックを確立します。アニメーションが開始される直前にJavaScriptを使用して動的に適用し、アニメーションが終了したら削除してください。スタイルシートに will-change を永続的に残さないでください。

このような状況にもかかわらず、2025年 Web Almanacの報告によると、モバイルページの40%が依然として非コンポジットアニメーションを実行しています。良いニュースは、CLSがモバイルで81%という最も高い合格率を誇るCore Web Vitalsであることです。悪いニュースは、もしあなたのサイトが不合格の19%に含まれている場合、まだ確認していないCSS transitionsが原因である可能性があることです。

About the author

Arjen Karel is a web performance consultant and the creator of CoreDash, a Real User Monitoring platform that tracks Core Web Vitals data across hundreds of sites. He also built the Core Web Vitals Visualizer Chrome extension. He has helped clients achieve passing Core Web Vitals scores on over 925,000 mobile URLs.

Lighthouseのスコアは全体像ではありません。

実ユーザーはAndroid端末で4Gを使っています。その人たちが実際に何を体験しているかを分析します。

フィールドデータを分析
CSS transitionsが引き起こすLayout ShiftCore Web Vitals CSS transitionsが引き起こすLayout Shift