Core Web Vitalsの中でもCLS(Cummulative Layout Shift)がなかなか改善しない、と悩んでいる方向けです。
例えばPageSpeed Insightsで分析かけて指摘事項直しているはずなのに、Search Console上でなかなか改善が見受けられない、など。
以下、その場合に見るべきことについて。
前提:フィールドデータとラボデータの違いを理解する
そもそもCWVで使用されるスコアはなにかを正確に理解しないと始まらないです。それらのスコアはPageSpeed Insightsのページを見ればわかりますが、実は一番上のスコアがCore Web Vitalsのスコアと思っていたらまず、そこから勘違いです。

じゃあこのスコアはなにかというと、ラボデータにある「パフォーマンススコア」の合計。もっと言ってみればどれくらいベストプラクティスちゃんとできているかのスコア。
一方、Core Web Vitalsは「LCP」「FID」「CLS」の3つの指標を指す。PSIのページではページ上部、中段にそれが載っている。

これが今回のCWVに関係する指標とそのスコア。ここに出ているスコアが合格ラインに達していないといけない。ちなみに合格ラインはこちら。
| Good | Needs improvement | Poor | |
|---|---|---|---|
| LCP | <=2.5s | <=4s | >4s |
| FID | <=100ms | <=300ms | >300ms |
| CLS | <=0.1 | <=0.25 | >0.25 |
そのままPSI見るとその下にも「LCP」と「CLS」がある。(「FID」はない。理由はシミュレートでは測定し得ない性質のものだから。近しいものとしては「Total Blocking Time」がある。)

先のデータと何が違うかと言うと、上の「フィールドデータ」は実際にユーザーの端末から得た生のデータで、「ラボデータ」はシミュレートしたデータ。
CWVが使用するのはあ言わずもがな上のフィールドデータ。ラボデータではない。
しかしPSIの下に出てくる指摘事項は、あくまでラボデータの内容に基づいて出てくるもの。
これが結構落とし穴。
フィールドデータに近い形でのレイアウトシフトの測り方
これでフィールドデータとラボデータの違いがわかったとして、じゃあどれくらい違うのか、といったら結構違う。特に今回の話題のCLSにおいてはその違いが顕著に出る傾向。大体フィールドデータのほうがラボデータより大きいのではないかと思う。
そしてPSIの下の方に出てくる指摘事項の中には、レイアウトシフトを起こした要素が列挙されているものの、それだけ直してもフィールドデータがなかなか改善しない、ということにもぶつかると思う。

なぜかと言うと、CLSに関してはフィールドデータとラボデータで計測方法が異なるから。
まずラボデータはページのloadのタイミングまでしか計測していない。つまりほぼAbove the foldと同じ。
一方フィールドデータはユーザーがunloadするまで累積で計測。(なお累積方法は新CLSの定義でSession Window単位)
Lab tools typically load pages in a synthetic environment and are thus only able to measure layout shifts that occur during page load. As a result, CLS values reported by lab tools for a given page may be less than what real users experience in the field.
https://web.dev/cls/
CLS is a measure of the largest burst of layout shift scores for every unexpected layout shift that occurs during the entire lifespan of a page.
https://web.dev/cls/
なので、だいたいユーザーがスクロールする範囲まで実際にスクロールして、それまでに累積されたCLSの値を見る、というやり方でないと、なかなか根本原因にたどり着けないし、CWVのCLSを改善できない。
それではそれをどうやるか、といったら以下方法がある。
- 調査したいページをブラウザ(Chrome)で開く
- DevToolsを開く
- Consoleパネルにて以下コードをコピペ、実行
- UI画面の方をスクロールして、Consoleに出た値を確認
let clsValue = 0;
let clsEntries = [];
let sessionValue = 0;
let sessionEntries = [];
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
// Only count layout shifts without recent user input.
if (!entry.hadRecentInput) {
const firstSessionEntry = sessionEntries[0];
const lastSessionEntry = sessionEntries[sessionEntries.length - 1];
// If the entry occurred less than 1 second after the previous entry and
// less than 5 seconds after the first entry in the session, include the
// entry in the current session. Otherwise, start a new session.
if (sessionValue &&
entry.startTime - lastSessionEntry.startTime < 1000 &&
entry.startTime - firstSessionEntry.startTime < 5000) {
sessionValue += entry.value;
sessionEntries.push(entry);
} else {
sessionValue = entry.value;
sessionEntries = [entry];
}
// If the current session value is larger than the current CLS value,
// update CLS and the entries contributing to it.
if (sessionValue > clsValue) {
clsValue = sessionValue;
clsEntries = sessionEntries;
// Log the updated value (and its entries) to the console.
console.log('CLS:', clsValue, clsEntries)
}
}
}
}).observe({type: 'layout-shift', buffered: true});


これでPSIだけでは出てこなかったレイアウトシフトを起こしている原因の特定ができるようになる。ここにたどり着けるかつけないかで、結構CLSを改善できるかできないかが決まってくる。
特にインリード、レコメンドウィジェットなど広告タグをたくさん入れていたり、また最近では画像を遅延読み込みしている媒体などでは上記使うことでより詳細に原因がわかるはず。(ニッチだが、画像の遅延読み込みの場合、最初にsrcにセットしている画像が1×1の画像でCSSでimg{width:100%;height:auto}などしているとき、本来の画像のアスペクト比が同じく1:1ならよいが、そうでない場合、レイアウトシフトが起きているケースが散見されるが当の媒体が気づいていないことも多い。)
CWVネタはまだあるがまずはCLSは最初の関門なので、気をつけよう、という話でした。