TL;DR
画像などが読み込まれたときに、ほかの要素を押し動かしてしまう現象。パフォーマンスの問題を引き起こし、Cumulative Layout Shift の値を悪くする。
なぜ必要か
web.dev によると、予期しないレイアウトシフトは、読んでいる位置を見失わせたり、間違ったリンクやボタンを押させたりする。キャンセルするつもりだった大きな注文を、ボタンの位置がずれたせいで確定してしまう、という例が挙げられている。
仕組み
web.dev の定義では、レイアウトシフトは見えている要素の位置がレンダリングのフレーム間で変わるたびに起きる。新しい要素を足しても既存の要素が動かなければ、レイアウトシフトには数えない。
ユーザの操作によるシフトは、操作の直後であれば問題ないとされる。クリックやタップ、キー入力から 500 ミリ秒以内のシフトは hadRecentInput の印が付き、CLS の計算から外せる。スクロールやドラッグはこの入力に含まれない。
例
web.dev は、よくある原因として次を挙げている。
- サイズが決まっていない画像や動画
- フォールバックのフォントと大きさが違うフォント
- 読み込み後に大きさが変わる広告やウィジェット
- 非同期に読み込まれ、既存のコンテンツの上に差し込まれる要素
注意点
画像によるレイアウトシフトを避けるには、画像のサイズを指定する必要がある。next/image では、import で読み込むか、width と height、または fill を指定してサイズを決める。
アニメーションでは、top や width などを変えるとレイアウトシフトになる。transform の translate() や scale() を使えば避けられる。