【実務・中級編】 Layout Instability API (CLS) – Webブラウザの仕組み実践ガイド

なぜ、ユーザーは「ボタンを押そうとした瞬間に逃げられる」のか? —— CLSとブラウザの裏側

現場で戦うエンジニアなら一度は経験があるはずだ。読み込み終わったと思ったサイトで、急に広告や画像がドンと割り込んできて、クリックしようとしたリンクが指先から逃げていくあの忌々しい体験。

あれこそが「CLS (Cumulative Layout Shift)」、つまり累積レイアウト変動だ。ユーザーにとっては単なる苛立ちだが、Googleからすれば「UXの欠陥」として検索順位を下げる立派な理由になる。今日は、このCLSの正体をブラウザの内部構造から紐解き、現場で使える武器に変えていこう。

ブラウザという「職人」の苦悩

ブラウザがHTMLを受け取って画面を描画するまで、実は裏側では凄まじい「後悔と修正」が繰り返されている。

1. DOM構築: HTMLをパースし、木構造を作る。
2. CSSOM構築: スタイルを読み込み、DOMに適用する。
3. Render Tree構築: DOMとCSSOMをマージして、「何を表示するか」を決める。
4. Layout: 各要素の「サイズ」と「位置」を計算する。
5. Paint: 実際にピクセルを塗りつぶす。

問題はLayout(4番目)だ。ブラウザは上から順にDOMをパースしていくが、例えば「高さ指定のない画像」が途中で読み込まれると、後からその要素のサイズが確定する。するとブラウザは、「しまった、下にある要素を全部押し下げなきゃ!」と、わざわざ再計算(Reflow)を走らせる。

この「後出しジャンケン」のようなレイアウト変更の積み重ねが、ユーザーの視覚的な安定性を破壊する。CLSは、この「ブラウザが泣きながら行っている再レイアウト」の距離と影響範囲を数値化したものなんだ。

実践:Layout Instability APIで「犯人」を特定する

「CLSが悪い」と言われても、大規模なサイトだとどこで起きているか特定するのは至難の業だ。そこでブラウザが提供しているのが `Layout Instability API` だ。これを使えば、どの要素がいつ、どれだけ動いたかをリアルタイムで追跡できる。

現場ですぐ使える、監視用のコードを書いてみた。これをデバッグ時にコンソールに貼るか、本番環境のログ収集スクリプトに組み込んでみてほしい。

// CLSの変動を監視し、どの要素が動いたか特定するスクリプト
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// entry.hadRecentInputがtrueなら、ユーザーの操作による変動なので
// 今回の評価(CLS)からは除外する(これが重要!)
if (!entry.hadRecentInput) {
console.warn(`[CLS検知] 変動量: ${entry.value.toFixed(4)}`);

// どの要素が原因で動いたか、ソースを特定する
const sources = entry.sources;
sources.forEach((source) => {
console.log(‘影響を受けた要素:’, source.node);
console.log(‘前後の矩形情報:’, source.previousRect, ‘->’, source.currentRect);
});
}
}
});

// layout-shiftというタイプを監視対象に登録
observer.observe({ type: ‘layout-shift’, buffered: true });

// ※注意:本番運用時は、この数値をGoogle Analytics等の計測基盤へ
// 送信する設計にすると、どのページでUXが損なわれているか一目瞭然になる。

現場の知恵:CLSを防ぐ「守り」の鉄則

このAPIを触るとわかるが、犯人は大抵決まっている。以下の3つを徹底するだけで、CLSは劇的に改善する。

  • 画像と動画には `width` と `height` を明示する:

`aspect-ratio` プロパティを使うのが現代のベストプラクティスだ。CSSで `aspect-ratio: 16 / 9;` と指定しておけば、画像が読み込まれる前からブラウザはその分の「空きスペース」を確保してくれる。これでレイアウトのズレは物理的に発生しなくなる。

  • 動的コンテンツの「場所」を確保する:

APIから取得したデータを表示するエリアには、あらかじめ `min-height` を設定しておくか、スケルトンスクリーン(プレースホルダー)を置いておく。

  • フォント読み込みの工夫:

Webフォントが読み込まれる瞬間にガクッと行間が変わる「FOUT」もCLSの温床だ。`font-display: swap` を使いつつ、代替フォントとサイズを調整して、切り替え時のズレを極限まで抑えるのがプロの仕事だ。

まとめ

ブラウザのレンダリングエンジンは、非常に優秀だが、あくまで「来た順に処理する」という基本原則がある。その原則を理解し、ブラウザが「後からサイズが変わって再計算する」という苦労をさせないように先回りして情報を与えてやる。

それが、我々フロントエンドエンジニアが「ブラウザを味方につける」ということだ。CLSを計測し、一つずつ潰していく。その泥臭い作業の先にしか、ユーザーに「心地よい」と言わせるサイトは存在しないんだ。

さあ、エディタを開いて、まずは自分のサイトのレイアウトが「暴れていないか」確認するところから始めよう。

コメント

タイトルとURLをコピーしました