2020年5月28日、Googleが正式にCore Web Vitals(コア・ウェブ・バイタル)を検索エンジンの検索結果に反映させると発表した。

本記事では、コアウェブバイタルの詳細と具体的な対応方法について解説する。

コアウェブバイタルとは

「Core Web Vitals」とは、GoogleがWebサイトのユーザー体験を測るうえで定義した指標。

Core Web Vitalsの中には、Largest Contentful Paint(LCP)、First Input Delay(FID)、Cumulative Layout Shift(CLS)の3項目が含まれている。

より快適なWebの実現に向けたページ エクスペリエンスの評価 出典:Google検索セントラルブログ

これは検索アルゴリズムの改善というよりも、ユーザーの体験価値(UX)を向上するためのガイドラインの制定といった意味合いが強い。

一般的に、表示速度が1秒遅くなると7%CVR(コンバージョン率)が下がる表示速度が1秒から3秒に落ちるとWebページの直帰率が32%上昇すると言われている。

したがって、Core Web Vitalsを対策した先には、Googleからの評価が高まるだけでなく、Webページ上でのユーザー体験が最適化されるという、より本質的で価値のある施策になる。

LCP(Largest Contentful Paint)

LCP @ web.dev

「最大コンテンツの描画」の意味で、ユーザーの認識としてのページ表示速度を測る指標。

ブラウザの表示範囲内で、最も大きなコンテンツ(画像・動画の初期表示画像・背景画像のある要素・テキストを含むブロックレベル要素など、そのページでメインとなるコンテンツ)が表示されるまでの時間を表す。

FID(First Input Delay)

FID @ web.dev

「初回入力遅延」の意味で、ユーザーが第一印象として感じるサイトのインタラクティブ性や反応速度を測る指標。

ユーザーが最初にページ内でアクションを行った際に(クリック・タップ・テキスト入力など)、その入力をブラウザが受け取り、処理を開始するまでにかかった時間を表す。(入力されてから行われる処理がすべて完了するまでの時間ではない点に注意)

CLS(Cumulative Layout Shift)

CLS @ web.dev

「累積レイアウト変更」の意味で、視覚要素の安定性を示す指標。

ユーザーが意図せぬレイアウトのずれがどれぐらい発生したかを、独自の「レイアウトシフトスコア」で表す。

具体的な評価基準と計測方法

Search Console

ある程度のトラフィックがあるWebサイトの場合はSearch Consoleからページ全体の評価を確認できる。

ウェブに関する主な指標 @ Web担当者Forum

PageSpeed Insights

Search Consoleで確認するにはトラフィックのデータが足りていない場合や、個別のページの評価を確認したい場合はPageSpeed Insightsを使用できる。

Google PageSpeed Insights Now Has Core Web Vitals Metrics

フィールドデータ(実際のユーザー行動に基づくデータ)が十分に集まっていなくても、ラボデータ(シミュレーション)を閲覧出来るのが利点である。

なお、参照項目は以下の通りだ。

  • LCP:最大コンテンツの描画
  • FID:合計ブロック時間
  • CLS:累積レイアウト変更

なお、FIDにおいては実際のユーザー行動によって計測が可能な項目であることから、厳密には合計ブロック時間=FIDではないため、参考までに確認する。

フィールドデータとラボデータの違い

Chrome拡張

Search ConsoleやPageSpeed Insightsを使用せずに簡易的に調査するのであれば Web Vitals を使用する。

Web Vitals

何をしなければいけないのか

コアウェブバイタルは2021年から実装予定で、かつ実装前(6ヶ月前まで)にアナウンスされることから、すぐに対応しなければならないわけではない。

一方で、コアウェブバイタルへの対応=UXの向上であり、施策が早すぎるということはないため、現時点で可能な施策を提示する。

LCPへの対応

LCPの改善項目は以下の4つだ。

  • サーバー応答の改善
  • リソース読み込み時間の削減
  • CSSやJavaScriptによるブロックの削減
  • クライアントサイドレンダリングの改善

サーバー応答の改善

サーバー応答速度を測る指標としてはTTFB (Time to First Bite)がある。

Chrome Dev Toolなどを用いてTTFBを確認する。

Googleはサーバー応答時間を200ミリ秒以下にすることを推奨しており、推奨値を上回っている場合は以下の施策を検討する。

  • サーバーの最適化
  • ユーザーから地理的に近いCDNを活用する
  • キャッシュの活用
  • HTMLページをキャッシュファーストで提供する
  • サードパーティーとの接続を早める

リソース読み込み時間の削減

Webサイトにおける一般的な「最大コンテンツ(LCP)」は画像や動画などのメディアであり、基本的にはこれらのメディアのサイズやフォーマットを最適化するなどして表示速度を向上させることが重要である。

具体的に、LCPは以下のHTML要素が表示されるまでの時間を対象としている。

  • img要素
  • image要素
  • video要素
  • 背景画像

具体的なファイル容量・フォーマットは以下を参考されたし。

画像の最適化

Googleが推奨するWebページ全体のファイル容量は1,600 KiB(1.6MB)であることから、1ページあたり5枚程度の画像を使用すると仮定すると、1画像あたりのファイルサイズは200KB程度に抑えたい。

ただし、この1.6MBというのは3G回線を前提としており、4Gが一般的な現在の情勢においては若干のサイズオーバーは許容範囲と考えられる。

ファイルサイズを意識して、あまりに圧縮しすぎると画質が下がりすぎてしまいUXに影響しかねないため、画質とファイルサイズのバランスを考慮したい。

元サイズ2.8MBの画像を圧縮した例。

低圧縮:550KB
高圧縮:300KB
高圧縮:150KB

150KBの場合、背景がまだら模様になってしまい、圧縮による劣化が目立ってしまう。
300KBの画像ではそういった劣化もあまり目立たず、550KBの画像と比較しても遜色はない。

なお、ファイル形式の特色は以下の通り。

PNG高画質の画像を生成するが、ファイルサイズも大きい。透過画像はPNGを使用する。
JPG(JPEG)多くのケースでPNGよりも軽量。画質とファイルサイズのバランス調整が容易。
GIFアニメーション画像に最適なフォーマット。場合によっては動画のほうが軽量。
「次世代フォーマットでの画像の配信」の解決方法
https://www.aiship.jp/knowhow/wp-content/uploads/2021/01/image4.png

「JPEG 2000、JPEG XR、WebP などの画像フォーマットは、PNG や JPEG より圧縮性能が高く、ダウンロード時間やデータ使用量を抑えることができます。」とあるように、よく見かけるPNGやJPEG ではなく、WebPのような画像データサイズを節約できる画像フォーマットが推奨されている。

PNGやJPGをWebPに変換する方法

以下のサイトでPNGとJPGをWebPに変換することができる。

WEBP変換ツール (jpg、pngとwebpを相互変換)

WebPを扱う上での注意点

WebP非対応のブラウザがあるという点には注意が必要。
以下のサイトではWebPがどのブラウザに対応しているかが分かる。

https://caniuse.com/?search=WebP

https://www.aiship.jp/knowhow/wp-content/uploads/2021/01/image2.png
WebPの対応ブラウザ

2021年1月の時点ではほとんどのブラウザに対応しているが、上記のサイトの赤色で示されている非対応ブラウザでは、WebPフォーマットの画像は表示されないので注意。

動画の最適化

動画のファイルサイズは画像と比較すると大容量になりがちで、1280px × 720pxの30秒程度の動画でも40MBを超えてしまい、そのままの状態でWebページに埋め込むと読み込み時間の大幅な遅延の原因となる。

背景にループ動画を流しているWebサイトをよく見かけるが、少なくとも5MB以下に圧縮しつつ、画質の低下をドット状のフィルターで目立たなくしたり、動画が読み込まれるまでの間に仮の背景を表示させるなどの工夫が必要。

また、比較的長い動画を高画質に見せたい場合はYoutube経由で動画を埋め込み、ストリーミング再生にすることでページ自体の読み込み時間を短縮することが可能。

さらに、10秒以内のループ動画を掲載したい場合にはGIF画像の使用も検討したい。

画像・動画の最適化と圧縮以外にも以下のような施策が検討できる。

  • 重要なリソースをプリロードする
  • テキストファイルを圧縮する
  • Adaptive servingの活用(ユーザーのデバイスや回線等の環境に応じて配信するファイルを変更する)
  • Service Workerを使ってキャッシュを利用する

CSSやJavaScriptによるブロックの削減

基本的に、CSSやJavaScriptはレンダリングを妨げるものであり、重要なレンダリングパスのパフォーマンスに影響を与えるものだ。

妨げるものか、妨げないものかに関わらず、ブラウザは全てのCSSやJavaScriptのリソースをダウンロードする。

CSS・JavaScriptの最小化、または圧縮

最小化は、不要な余白やコードを取り除くことも含む。JavaScriptの圧縮ツールを使うと効果的である。

圧縮では、サーバーとクライアントの連携をスムーズにするために、データフォーマットをアルゴリズム的に変更する。

Webサイトがモジュールバンドラーやビルドツールを使用している場合、スクリプトをシステム的に最小化してくれるプラグインの導入を検討する。

クリティカルでないCSSを遅延させる

DevToolsのCode Coverageのレポートは、ページ内のどのスタイルが使用されているかを特定する手助けとなる。どのページでも使用されていないのであれば、完全に削除してしまう(CSSファイルはすぐに肥大化してしまう)。

他のページで使用されている場合は、そのページのために別のスタイルシートを作成し、呼び出すようにする。

未使用のJavaScriptを遅延させる

コードスプリッティングでは、JSの大きな塊を、小さなパッケージに分割する。
そうすることで、ファーストビューのコンテンツで必要なものを先にロードすることが可能となる。

クリティカルなCSSのインライン化

(Code Coverageのレポートで特定することができた)ファーストビューのコンテンツで使用される、クリティカルなCSSを内に直接記載する。

動的なメディアクエリの使用

メディアクエリとは、CSSに適用される、シンプルなフィルタであり、コンテンツをレンダリングするデバイスの種類に応じて、スタイルを分割してくれる。

動的なメディアクエリを使用することは、全てのビューポートのスタイルを計算するのではなく、リクエストしたビューポートに応じた値を呼び出し、計算することを意味する。

クライアントサイドレンダリングの改善

Reactなどを用いてSPA (Single Page App)を作成している場合は特に、クライアントサイドでのレンダリングが負荷をかけていないかどうかに注意する必要がある。

単発的な調査では、ページのソースを見る。ちんぷんかんぷんな数行の文字が書かれていた場合は、そのページはクライアントサイドレンダリングである可能性が高い。

ページ内の要素がクライアントサイドレンダリングである場合もある。
該当する要素を発見するために、初回のページソースと、レンダリングされた後のHTMLを比較してみよう。クローラーを使用している場合は、レンダリングされた後のHTMLの単語数の違いを見てもよい。

Core Web Vitalsは、レンダリングの方法がどの程度効果的かを見るための手段とも言える。

どのレンダリングの方法でもアウトプットは同じである(いずれもWebページを構築する)。
しかし、CWVは、重要な要素が、重要なときに、どの程度早く提供されているかを測定する。

「オーガニックのトラフィックが減少したタイミングで、どのような変更が本番環境に施されたのか?」という疑問が無い限り、クライアントサイドレンダリングが答えとなることはない。

改善方法には以下のようなものがある。

  • JavaScriptの最小化
  • プリレンダリングの使用(JavaScriptの非同期化)
  • サーバーサイドレンダリングの使用
プリレンダリングの使用(JavaScriptの非同期化)

ビルド時にスクリプトを実行し、レンダリングされたHTMLをリクエストに対応させる。
この方法は、サーバーのレスポンスが良くなるものの、在庫や値段が頻繁に変わるWebサイトには使用できない。

サーバーサイドレンダリングの使用

サーバーに JavaScript の要素を実行させることで、完全にレンダリングされたHTMLを返すことができる。しかし、サーバーの応答の前にスクリプトが実行させるため、TTFBが増加することには気を付ける。

FIDへの対応

FIDでは、ユーザーがそのページ内で最初に行うアクション(クリック・タップ・スクロール・文字入力など)に対して反応を返すのに要した時間のことであり、Webページの技術要件(htmlの構造やjsによる遅延の影響など)によって対応は異なる。

例えば、ユーザーが「読み込みが完了した」と判断してスクロールしようとしたが、Webページ側ではまだ読み込みが完了しておらずスクロール操作を受け付けない・遅延が発生するケースだ。

この場合は、

  • 常にその操作を受け付けるようにページ内での読み込み優先度をあげる
  • 読み込みが完了していない間はその要素を表示しない・見えないようにする

といった対応が考えられる。

具体的な改善方法としては以下が考えられる。

  • サードパーティコードを考慮する
  • メインスレッドの作業を分割/最小化する
  • インタラクションに対応するためのページ最適化

サードパーティコードを考慮する

広告や分析用などのサードパーティタグがインタラクションの待ち時間に影響を与える可能性がある。

たとえば、ファーストビューの外にある広告は、その近くまでスクロールしたときにはじめて読み込まれるようにするなど、必要な時に読み込めるようにできないかを検討する。

メインスレッドの作業を分割/最小化する

巨大な JavaScript のバンドルを全てのページに配布しているのであれば、そのページでは使用されない機能が含まれている可能性がある。

使用されていないにもかかわらず、それぞれの JavaScript の機能はダウンロードされ、解析され、コンパイルされ、実行されてしまう。

このような巨大になバンドルを小さな塊に分割し(コード分割)、使用される機能だけを配布する(ツリーシェイク)ことで、メインスレッドを開放することができる。

インタラクションに対応するためのページ最適化

JavaScript バンドルの配布と実行を、重要順に行う。

ファーストビューで使用する場合、rel=preload を使用して優先的に表示させる。

重要ではあるが、レンダリングをブロックするほどではない場合、async属性 を追加する。

ファーストビュー以外の要素の場合、defer属性 で遅延させる。

CLSへの対応

CLSの評価が低い場合、ユーザーが見ているコンテンツが後から読み込まれたコンテンツによって押し出される(位置がズレる)現象が発生している。

Impact fraction @ web.dev

具体的には以下のような原因で発生する。

  • 画像、広告など埋め込まれる要素にサイズが指定されていない
  • コンテンツが動的に埋め込まれる
  • Webフォントの読み込み

具体的な改善方法としては以下が考えられる。

  • 画像や広告のスペースを確保する
  • 既存のコンテンツの上に新しいコンテンツを挿入することを避ける
  • フォントと重要なリソースのプリロード
  • ファーストビューのコンテンツに必要なリソースのチェーンを避ける
  • document.write() を避ける

画像や広告のスペースを確保する

画像と動画の要素には、常にwidthとheightのサイズ属性を付与する。

<img src="stable-layout.jpg" width="640" height="360"> のように書けばよい、という単純なものではないこともある。レスポンシブウェブデザインの場合、heightとwidthの宣言が減少している。これは、画像が表示されるとページがリフローしてしまうという悪影響も招いている。

ベストプラクティスは、ユーザーエージェントのスタイルシートを活用し、画像のアスペクト比に応じて、システム的にディメンションを宣言することである。

広告に関しては、最も大きいサイズの広告を特定し、領域を確保するという方法を採ることになる。
広告が表示されない場合に備え、プレースホルダーを設置する。
そのギャップは、レイアウトシフトの変更よりもマシであるはずだ。

画像と動画の要素には、常にwidthとheightのサイズ属性を付与する。

<img src="stable-layout.jpg" width="640" height="360"> のように書けばよい、という単純なものではないこともある。レスポンシブウェブデザインの場合、heightとwidthの宣言が減少している。これは、画像が表示されるとページがリフローしてしまうという悪影響も招いている。

ベストプラクティスは、ユーザーエージェントのスタイルシートを活用し、画像のアスペクト比に応じて、システム的にディメンションを宣言することである。

広告に関しては、最も大きいサイズの広告を特定し、領域を確保するという方法を採ることになる。
広告が表示されない場合に備え、プレースホルダーを設置する。
そのギャップは、レイアウトシフトの変更よりもマシであるはずだ。

7月6日 追記

既存のコンテンツの上に新しいコンテンツを挿入することを避ける

ビューポートの上部に、固定でない広告を表示する場合は要注意。

一般論として、ページの上部には広告を表示しないほうがよい。
Google Search Consoleの新しいレポートにて、フラグが立てられるだろう。

ファーストビューのコンテンツに必要なリソースのチェーンを避ける

チェーンは、「リソースを呼び出すリソース」を呼び出す際に発生する。
クリティカルなアセットがスクリプトによって呼び出された場合、そのスクリプトが実行されるまで、そのアセットを呼ぶことはできない。

document.write() を避ける

最新のブラウザは、メインスレッドの投機的解析をサポートしている。

スクリプトがダウンロードされ、実行されている間に、先読みして作業を行う。
先読みしている際、document.write()が挿入され、中身を書き換えてしまうようなもので、先んじて読んでいた内容が無駄になってしまう。

フォントと重要なリソースのプリロード

フォントの読み込みが遅れた場合、書き直しが発生する。

プリロードは、そのフォントがページにとって重要であるため、ブラウザが発見するよりも早く取得して欲しい旨を、ブラウザに伝えることができる。

ただし、プリロードだけではCLSが改善しない場合がある。
再描画を防ぐことでこの問題を解消することができるかもしれない。

Webフォントのプリロードと再描画

特にWebフォントはCLSへの影響が大きく、その要因として下記が考えられる。

  1. ページ表示後にWebフォントが再描画
  2. 文字の大きさや幅が変化
  3. レイアウトが移動
  4. CLSが悪化

以上から、Webフォントを使いながらもCore Web Vitalsに影響しない為には、上記1~3の発生をいかに防ぐかがポイントとなる。

font-display:optionalを利用する

font-display とは、Webフォントが描画できるまでの間、どのように表示するかを指定できるプロパティとなり、下記のようにCSSで指定できる。

ブラウザのデフォルトは「font-display: auto」

font-displayを指定しない場合、「auto」が適用される。
この「auto」の挙動は下記の通り。

  1. 2~3秒の間、Webフォントの描画を試みる 
  2. 2~3秒以内に描画出来ない場合は、ローカルフォントで表示
  3. Webフォントで描画できるタイミングで、フォントを変える

上記の流れにおいて、2 の「一旦、ローカルフォントで表示」が入ってしまう為、3 の「Webフォントで再描画」の時にレイアウトシフトが発生してしまう。

ブラウザのデフォルト設定である「一旦、ローカルフォントで表示」が、結果的にCLSの悪化を招いている状態。
「optional」で再描画を防ぐ

「再描画」は font-display の「auto」や「swap」、「block」などが該当し、Core Web Vitalsの観点からはこれら値を font-display に設定する事はできない。

ここで利用するのが「optional」。

font-display: optional の挙動は、

  1. 100ミリ秒はWebフォントの描画を試みる
  2. それ以上時間がかかる場合はローカルフォントで表示
  3. ローカルフォントが表示されたら再描画しない

になり、基本方針の「再描画させない」にマッチする。

font-display とCLSへの影響

つまり、「Webフォントの描画は約束しないが、レイアウトはズラさない」という挙動であり、Core Web Vitalsの面では適切な選択肢といえる。

font-display: optional を利用する事で、「Webフォントの再描画」を防ぐ事はできたが、「100ミリ秒以内にWebフォントを読み込み、描画できる状態に無ければならない」という課題がある。

この点を対処しないと、レイアウトシフトは発生しないがWebフォントで表示されない、という本末転倒な状態に陥る。

そこで必要なのが「ローディング時間の短縮化」である。

ローディング時間の短縮化

font-display:optional を利活用する為にも、Webフォントのファイルを素早くWebブラウザにダウンロードさせ、いち早く描画できる状態にしなければならない。

英語と比較し、文字数が多い日本語は当然フォントファイルのサイズも大きくなる。

Webフォントのファイルサイズが大きければ、ダウンローディング(読み込み)とレンダリングにも時間を要してしまう。

そこで重要になるのが、Webフォントのローディング時間の短縮化である。

Webフォントを軽量化(サブセット化)

日本語のフォントには、普段あまり使われない漢字などが含まれる。
フォント「全部入り」の状態から日常的に使われるフォントのみを抽出する事で、フォントファイルそのものを軽量化(サブセット化)する。

サブセット化の方法(参考)

サブセット化する文字は「日本語WEBフォントをサブセット化する際の参考文字列一覧」の「JIS第1水準+常用漢字+その他でまとめると」を利用する。

サブセットフォントメーカーを使って、Webフォントを軽量化する。

Webフォントフォーマットの変更

メジャーどころのWebフォントフォーマットとして下記4つがある。

  • EOT:IEのみに対応している
  • TTF:WindowsやMacで標準的に利用されるフォント
  • WOFF:Web向けのフォント
  • WOFF2:WOFFの圧縮形式を改善し、軽量化したフォント

「Webフォント」として利用するのであれば、圧縮率の観点からWOFFもしくはWOFF2を利用するのが望ましい。

Webフォントは、CSSを通して読み込むフォントファイルやフォーマット、Class名を指定する。

@font-face {
    font-family: "notoSnas";
    src: url("NotoSansCJKjp_AFTER.woff2") format("woff2"),
         url("NotoSansCJKjp_AFTER.woff") format("woff");
}

上記のように、複数のフォントフォーマットを format(); で指定出来るようになっている。

同じフォントを異なるフォーマットで複数回指定しても、全てが読み込まれる事はない。ブラウザが自動的に判断し、自ら対応している最善のフォーマットを1つ選んでくれる。

HTTP/2とファイル分割

ローディング時間を短縮する方法に「Webフォントのファイルを細かく別けて、それらファイルを同時に一度で取得する」がある。

HTTP/2とファイル分割による高速化

複数のHTTP通信が同時に行えるようになったHTTP/2を活用し、ファイルサイズが大きいWebフォントのダウンロードを速くする方法。

Google Fontsでは既にこの方法が実装されており、ファイルサイズが大きいNotoSansを100個近くに分割し、HTTP/2で同時送受信している。

font-display: optional を利用するには、100ミリ秒以内にWebフォントを読み込み、描画に移らなくてはならない。

しかし、この「100ミリ秒」はとても短く、軽量化したWebフォントでもダウンロードに90ミリ秒近くかかってしまう。

※状況やファイルによって異なる

HTTP/2とファイル分割によってこのダウンロード時間を短縮する事は可能だが、ダウンロード→読み込み→描画という3つの工程を短い時間でこなすには、もう一つ重要な対処がある。

描画に必要なファイルを先にロードする

いち早くWebフォントの描画に移るには、Webフォントのファイルを優先的にロードする必要がある。

ここで利用するのが preload である。

軽量化したWebフォントファイルを preload で先読みする事で、font-display:option による100ミリ秒以内での描画に備える。

また、キャッシュとしてブラウザ内に保存されているWebフォントも preload を用いる事で先にキャッシュから呼び出し、高速に描画できるようになる。