LCPの改善方法について
※本記事はweb.devを学習用にまとめたものです。解釈に齟齬等あればコメントください。
Overview
Googleで提唱されているWebページのパフォーマンス指標である LCP (Large Contentfull Paint) を最適化する具体的な手法について記載する。
LCPとは何かについては、Web Vitalsとは何かを参照してください。
LCPが悪化する4つの原因
1. サーバーレスポンスタイムが遅い
サーバーからのレスポンスが遅くなれば、当然画面へのレンダリング処理も遅くなる。
遅くなってるかどうかはTime to First Byte (TTFB)を計測すべし。
もしTTFBが遅いコンテンツに対して、レスポンスタイムを改善すればLCPも最適化できる。
2. JavaScriptやCSSによるレンダリングブロック
<link>
や<script>
のタグがあると、HTMLのパースが一時停止する。
HTMLのパースが完了しないと、レンダリングが始まらない。
従って、JSとCSSの読み込み方次第で、レンダリングの速度も改善する。
3. 動画像読み込みが遅い
<img>
, <svg>
, <video>
, url()
などが様々な動画像を読み込めば、当然描画時間に影響を与える。
たとえば、Above the fold(スクロールしないで見える領域)に画像コンテンツとかが多ければ、それだけLCPは劣化する。
4. クライアント側でのレンダリング処理
React, Vue, AngularなどでSPAを構築するときは注意が必要。
なぜなら、JavaScriptのダウンロードと実行が完了しないと、クライアント側には何も描画されないから。
どうすれば改善する??
計測して原因が特定できたら、あとは改善あるのみ
共通して言えることは、
- コンテンツのサイズを縮小する
- できるだけキャッシュさせる
- 初期表示に不要なコンテンツは遅延読み込み
- 初期表示に必要なコンテンツは事前読み込み
1. サーバーレスポンスタイムの改善
サーバー側の最適化
サーバ側がリクエストを受けてから、重たいロジックを処理したり、重たいSQLを流したりするとレスポンスは悪化する。
基本的にはフレームワークを使って動的なコンテンツを返しているはずなので、フレームワークごとのパフォーマンスガイダンスに従うがよし。
CDN&キャッシュの利用
ユーザから物理的に近い場所からレスポンスを返す、できるだけキャッシュで返す。
様々なレイヤでのキャッシュが利用できるため、検討すべし。
Service Workerの利用
バックグラウンドでService Workerを動かすことで、細かなキャッシュ制御ができる。
統計的にもService Workerが有効なサイトはLCPが小さいため、導入を検討すべし。
外部リソース取得時の事前接続
レンダリングに重要なコンテンツを外部から取得するときも、LCPに影響を与える。
preconnectやdns-prefetchを使うことで、ブラウザはあらかじめコネクションを確立することが可能。
<head>
…
<link rel="preconnect" href="https://example.com" />
<link rel="dns-prefetch" href="https://example.com" />
</head>
2. JavaScriptやCSSの読み込みを最適化
CSS/JSのMinify
空白, インデント, コンマなど不要な文字を取り除く
NON-criticalなCSS/JSの遅延読み込み
初期表示で必要なもの不要なものに分割し、不要なものは遅延読み込みをさせる。
<link rel="preload" href="stylesheet.css" as="style" onload="this.rel='stylesheet'">
criticalなスタイルのインライン化
above-the-foldに必要なスタイルは<head>
内に直接埋め込む
使用しないpolyfillsの最小化
対応するブラウザの種類やバージョンを決めて、babelなどを利用して最適化する
Serve modern code to modern browsers for faster page loads
3. リソースの読み込みを最適化
画像サイズの圧縮と最適化
不必要なものを除去、圧縮、フォーマット変換(WebP)を検討すべし。
重要な画像のプリロード
CSSやJSから新たにコンテンツを取得し、それがレンダリングに必要なものであればプリロードさせる。
例えば、HEROの動画像やフォントファイルなどが該当する。
<link rel="preload" as="script" href="script.js" />
<link rel="preload" as="style" href="style.css" />
<link rel="preload" as="image" href="img.png" />
<link rel="preload" as="video" href="vid.webm" type="video/webm" />
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin />
テキストファイルの圧縮
gzipやBrotliなどのアルゴリズムにより、サーバ側で圧縮して配信するように設定する。
ユーザ環境に適応したリソース選択
ユーザのネットワーク速度などの環境に応じて、配信するコンテンツの種類やサイズを選択させる。
使用可能なユーザ環境の例)
-
navigator.connection.effectiveType
: 接続回線の種類 -
navigator.connection.saveData
: データセーバー設定の有無 -
navigator.hardwareConcurrency
: CPUコア -
navigator.deviceMemory
: メモリ
Service Workerによるキャッシュ
Service Workerでキャッシュ制御をさせると、静的コンテンツを何度も取得させる必要がなくなる。
特に、回線速度が遅い端末に対しては効果的。
4. レンダリング処理の最適化
JavaScriptの最小化
JavaScriptやCSSの読み込みを最適化での議論と同じ
SSR(Server Side Rendering)の利用
サーバ側でHTMLをレンダリングさせることで、SPAの欠点とされている
「JavaScriptがすべて読み込まれないと何も表示されない」
という問題が解決する。
一方で、レスポンスタイムが悪化したり、TTI(操作するまでの時間)が悪化する恐れもある。
SSG(Static Site Generator)の利用
SSRの欠点である「レスポンスタイムの悪化」を補うために、事前に静的コンテンツをビルドしておくという手法。
しかしながら、TTIの悪化は解決できない。
感想
大事なことは「上に書いてあること全部やる」じゃなくて
「自分のサイトでのボトルネックを測定して対処する」、な気がする。
全部やると結構大変そうだし、トレードオフも発生しそう。
Discussion