クリティカル パスを理解する

クリティカル レンダリング パスとは、ウェブページがブラウザでレンダリングを開始するまでの手順を指します。ページをレンダリングするには、ブラウザに HTML ドキュメント自体と、そのドキュメントのレンダリングに必要なすべての重要なリソースが必要です。

HTML ドキュメントをブラウザに取得する方法については、前回のHTML の一般的なパフォーマンスに関する考慮事項モジュールで説明しました。このモジュールでは、ページをレンダリングするために HTML ドキュメントをダウンロードしたのブラウザの動作について詳しく説明します。

プログレッシブ レンダリング

ウェブは本質的に分散型です。使用前にインストールされるネイティブ アプリケーションとは異なり、ブラウザは、ページのレンダリングに必要なすべてのリソースがウェブサイトにあることを前提とすることはできません。そのため、ブラウザはページを段階的にレンダリングするのに非常に適しています。通常、ネイティブアプリにはインストール フェーズと実行フェーズがあります。ただし、ウェブページとウェブアプリの場合、これらの 2 つのフェーズ間の境界ははるかに不明確であり、ブラウザはそれを念頭に置いて特別に設計されています。

通常、ブラウザはページをレンダリングするためのリソースを取得すると、レンダリングを開始します。そのため、レンダリングのタイミング(早すぎるタイミング)を選択する必要があります。

ブラウザが HTML が届いた時点でできるだけ早くレンダリングを開始し、CSS や必要な JavaScript が届く前にレンダリングを完了すると、ページが一時的に破損したように見え、最終的なレンダリングで大幅に変更されます。これは、ブラウザが最初のレンダリングに必要なリソースをより多く取得し、ユーザー エクスペリエンスを向上させるまで、最初にしばらく空白の画面を表示するよりも悪いエクスペリエンスです。

一方、ブラウザが順次レンダリングを行うのではなく、すべてのリソースが利用可能になるまで待機すると、ユーザーは長時間待機することになります。ページがずっと前に使用可能だった場合は、不必要に待機することになります。

明らかに機能しないエクスペリエンスを表示しないように、ブラウザは待機するリソースの最小数を把握する必要があります。一方で、ブラウザはコンテンツをユーザーに表示する前に、必要以上に待機することもできません。ブラウザが最初のレンダリングを実行する前に行う一連のステップは、クリティカル レンダリング パスと呼ばれます。

クリティカル レンダリング パスを理解することで、最初のページのレンダリングを必要以上にブロックしないようにし、ウェブ パフォーマンスを改善できます。ただし、最初のレンダリングに必要なリソースをクリティカル レンダリング パスから削除して、レンダリングが早すぎることを許さないことも重要です。

(クリティカル)レンダリング パス

レンダリング パスは次のステップで構成されています。

  • HTML からドキュメント オブジェクト モデル(DOM)を構築する。
  • CSS から CSS オブジェクトモデル(CSSOM)を構築する。
  • DOM または CSSOM を変更する JavaScript を適用する。
  • DOM と CSSOM からレンダリング ツリーを構築する。
  • ページでスタイルとレイアウトの操作を行い、どの要素がどこに適しているかを確認します。
  • メモリ内の要素のピクセルをペイントします。
  • ピクセルが重なっている場合は、それらを合成します。
  • 結果として得られたすべてのピクセルを物理的に画面に描画します。
HTML と CSS からピクセルの表示までのレンダリング プロセス。
レンダリング プロセス(上記のリストに詳細を記載)。

これらの手順がすべて完了すると、画面にコンテンツが表示されます。

このレンダリング プロセスは複数回行われます。最初のレンダリングでこのプロセスが呼び出されますが、ページのレンダリングに影響するリソースが利用可能になると、ブラウザはこのプロセス(またはその一部)を再実行して、ユーザーに表示される内容を更新します。クリティカル レンダリング パスは、最初のレンダリングについて前述のプロセスに焦点を当てており、それに必要なクリティカル リソースに依存します。

クリティカル レンダリング パスにあるリソース

ブラウザは、重要なリソースのダウンロードが完了するまで待ってから、最初のレンダリングを完了する必要があります。次のようなリソースが該当します。

  • HTML の一部。
  • <head> 要素内のレンダリングを妨げる CSS。
  • <head> 要素内のレンダリングを妨げる JavaScript。

重要な点は、ブラウザが HTML をストリーミング形式で処理することです。ブラウザは、ページの HTML の一部を取得するとすぐに、その処理を開始します。ブラウザは、ページの残りの HTML を受信する前に、この広告をレンダリングすることを決定できます。

重要な点は、通常、ブラウザは初回レンダリング時に以下を待機しません

  • すべての HTML。
  • フォント
  • 画像
  • <head> 要素外のレンダリングをブロックしない JavaScript(HTML の末尾に配置された <script> 要素など)。
  • <head> 要素の外部にあるレンダリングをブロックしない CSS、または現在のビューポートに適用されない media 属性値を持つ CSS。

フォントと画像は、ブラウザによって、後続のページの再レンダリング時に入力されるコンテンツと見なされることがよくあります。そのため、初期レンダリングを遅らせる必要はありません。ただし、フォントが読み込まれるまで、または画像が利用可能になるまで、テキストが非表示になっている間、空白の領域が最初のレンダリングに残る可能性があります。さらに悪いことに、特定の種類のコンテンツに十分なスペースが予約されていない場合(特に HTML に画像のサイズが指定されていない場合)、このコンテンツが後で読み込まれたときにページのレイアウトがずれる可能性があります。ユーザー エクスペリエンスのこの側面は、Cumulative Layout Shift(CLS)指標で測定されます。

<head> 要素は、クリティカルなレンダリング パスを処理するうえで重要です。そのため、次のセクションで詳しく説明します<head> 要素の内容を最適化することは、ウェブ パフォーマンスの重要な要素です。ただし、現時点では、重要なレンダリング パスを理解するために、<head> 要素にはページとそのリソースに関するメタデータが含まれ、ユーザーが実際に表示できるコンテンツは含まれていないことを理解しておくだけで十分です。表示されるコンテンツは、<head> 要素の後に続く <body> 要素内に含まれます。ブラウザがコンテンツをレンダリングするには、レンダリングするコンテンツと、レンダリング方法に関するメタデータの両方が必要です。

ただし、<head> 要素で参照されるリソースのすべてが、最初のページのレンダリングに厳密に必要というわけではありません。そのため、ブラウザは必要なリソースのみを待機します。クリティカル レンダリング パスにあるリソースを特定するには、レンダリング ブロックとパーサー ブロックの CSS と JavaScript を理解する必要があります。

レンダリングをブロックするリソース

一部のリソースは非常に重要と見なされ、ブラウザはリソースを処理するまでページのレンダリングを一時停止します。CSS はデフォルトでこのカテゴリに分類されます。

ブラウザは、<style> 要素の内部 CSS であるか、<link rel=stylesheet href="..."> 要素で指定された外部参照リソースであるかにかかわらず、CSS を検出すると、その CSS のダウンロードと処理が完了するまで、コンテンツのレンダリングを停止します。

リソースがレンダリングをブロックするからといって、ブラウザが他の処理を停止するとは限りません。ブラウザは可能な限り効率的に動作しようとするため、CSS リソースのダウンロードが必要と判断すると、リソースをリクエストしてレンダリングを一時停止しますが、残りの HTML の処理は続行し、その間に他の処理を探します。

CSS などのレンダリング ブロック リソースは、検出されるとページのすべてのレンダリングをブロックしていました。つまり、一部の CSS がレンダリング ブロックであるかどうかは、ブラウザがそれを検出したかどうかによって異なります。一部のブラウザ(最初は Firefox、現在は Chrome も)は、レンダリングをブロックするリソースの下にあるコンテンツのレンダリングのみをブロックします。つまり、クリティカルなレンダリング ブロック パスでは、通常、<head> 内のレンダリング ブロック リソースに注目します。これは、ページ全体のレンダリングを効果的にブロックするためです。

比較的最近のイノベーションとして、Chrome 105 に追加された blocking=render 属性があります。これにより、デベロッパーは、要素が処理されるまで <link><script>、または <style> 要素をレンダリング ブロッキングとして明示的にマークできますが、その間もパーサーはドキュメントの処理を続行できます。

パーサーをブロックするリソース

パーサーをブロックするリソースとは、HTML の解析を継続して、ブラウザが他の処理を探すのを妨げるリソースです。JavaScript は実行時に DOM または CSSOM を変更できるため、デフォルトではパーサー ブロッキングになります(非同期または遅延として明記されている場合を除く)。そのため、リクエストされた JavaScript がページの HTML に及ぼす影響を完全に把握するまで、ブラウザは他のリソースの処理を続行できません。そのため、同期 JavaScript はパーサーをブロックします。

パーサーをブロックするリソースは、レンダリングをブロックするリソースでもあります。パーサーは、解析をブロックしているリソースが完全に処理されるまで、その先に進むことができないため、その先のコンテンツにアクセスしてレンダリングできません。ブラウザは待機中にこれまでに受信した HTML をレンダリングできますが、重要なレンダリング パスが懸念される場合、<head> 内のパーサー ブロッキング リソースは、ページ コンテンツがすべてレンダリングされないようにします。

パーサーをブロックすると、レンダリングをブロックするだけよりもはるかに大きなパフォーマンス コストが発生する可能性があります。このため、ブラウザは、プリロード スキャナと呼ばれるセカンダリ HTML パーサーを使用して、メインの HTML パーサーがブロックされている間に今後のリソースをダウンロードすることで、このコストを削減しようとします。HTML を実際に解析するほどではありませんが、少なくともブラウザのネットワーク機能がブロックされたパーサーの前に動作できるため、今後再びブロックされる可能性は低くなります。

ブロックしているリソースを特定する

多くのパフォーマンス監査ツールは、レンダリングとパーサーのブロックを発生させるリソースを特定します。WebPageTest では、レンダリングをブロックするリソースは、リソースの URL の左側にオレンジ色の円でマークされます。

WebPageTest によって生成されたネットワーク ウォーターフォール図。パーサーをブロックするリソースは、リソースの URL の左側にオレンジ色の円で示され、レンダリング開始時間は濃い緑色の線で示されます。
WebPageTest によって生成されたネットワーク ウォーターフォール図。

レンダリングを開始するには、レンダリングをブロックするすべてのリソースをダウンロードして処理する必要があります。これは、ウォーターフォール内の濃い緑色の線で示されます。

Lighthouse でもレンダリングをブロックするリソースがハイライト表示されます。ただし、リソースが実際にページのレンダリングを遅らせた場合のみ、より目立たない方法でハイライト表示されます。これは、レンダリング ブロックを最小限に抑えている場合に、誤検出を回避するのに役立ちます。Lighthouse で、上の WebPageTest の図と同じページ URL を実行すると、レンダリングをブロックするリソースとして識別されるのは、スタイルシートの 1 つだけです。

Lighthouse によるレンダリングをブロックするリソースの除去に関する監査。監査には、レンダリングをブロックするリソースと、ブロックされた時間が表示されます。
レンダリングを妨げるリソースを除外するための Lighthouse の監査。

クリティカル レンダリング パスを最適化する

クリティカル レンダリング パスを最適化するには、前述のモジュールで詳しく説明したように、HTML を受信するまでの時間を短縮し(Time to First Byte(TTFB)指標で表されます)、レンダリングをブロックするリソースの影響を軽減する必要があります。これらのコンセプトについては、次のモジュールで説明します。

重要なコンテンツを含むレンダリング パス

長い間、クリティカル レンダリング パスは最初のレンダリングに重点を置いてきました。しかし、ウェブ パフォーマンスに関するユーザー中心の指標が登場したことで、クリティカル レンダリング パスの終点が最初のペイントであるべきか、その後に続くコンテンツを含むペイントのいずれであるべきかについて疑問が提起されています。

別の視点として、コンテンツ レンダリング パス(またはキーパス)の一部として、Largest Contentful Paint(LCP)(または First Contentful Paint(FCP))までの時間に注目することもできます。この場合、クリティカル レンダリング パスの一般的な定義ではブロックとは見なされませんが、コンテンツを含むペイントのレンダリングに必要なリソースを含める必要があります。

「クリティカル」と定義する内容の正確な定義にかかわらず、初期レンダリングと主要なコンテンツの遅延の原因を把握することが重要です。ファースト ペイントは、ユーザーに対して何かをレンダリングする最初の機会を測定します。理想的には、背景色などではなく、意味のあるものである必要がありますが、コンテンツがなくても、ユーザーに何かを表示することには価値があります。これは、従来定義されているようにクリティカル レンダリング パスを測定する理由となります。同時に、メイン コンテンツがユーザーに表示されたタイミングを測定することも価値があります。

コンテンツを含むレンダリング パスを特定する

多くのツールで、LCP 要素とそのレンダリングのタイミングを特定できます。Lighthouse では、LCP 要素に加えて、LCP の各フェーズと各フェーズに費やされた時間も特定できるため、最適化の取り組みを集中させるべき場所を把握できます。

Lighthouse の LCP 監査: ページの LCP 要素と、TTFB、読み込み遅延、読み込み時間、レンダリング遅延などのフェーズで費やした時間が表示されます。
Lighthouse の LCP 監査。

複雑なサイトの場合、Lighthouse は別の監査で重要なリクエストのチェーンもハイライト表示します

Lighthouse のクリティカル リクエスト チェーン図。他のクリティカル リソースの下にネストされているクリティカル リソースと、クリティカル リクエスト チェーンに関連する合計レイテンシを示します。
Lighthouse の重要なリクエスト チェーンの図

この Lighthouse 監査では、優先度の高いすべてのリソースが監視されます。そのため、実際にレンダリングをブロックしていなくても、Chrome が優先度の高いリソースとして設定したウェブフォントなどのコンテンツが含まれます。

理解度テスト

クリティカル レンダリング パスとは

ページを完全にレンダリングするために必要な最小限のリソース量。
もう一度お試しください。
最初のページのレンダリングに必要な最小限のリソース量。
正解です。

クリティカル レンダリング パスにはどのようなリソースが関与していますか?

HTML の一部。
正解です。
<head> 要素のレンダリングをブロックする CSS。
正解です。
<head> 要素内のレンダリングを妨げる JavaScript。
正解です。

レンダリング ブロックがページ レンダリングに必要な部分である理由

ページが最初に使用できない状態や明らかに破損した状態になる事態を防ぐため。
正解です。
ページが完全にレンダリングされるまで、ユーザーにページが表示されないようにする。
もう一度お試しください。

JavaScript が HTML パーサーをブロックするのはなぜですか(<script> 要素に deferasync、または module 属性が指定されていない場合)?

これらの属性の少なくとも 1 つがないと、<script> はパーサー ブロッキングとレンダリング ブロッキングになります。
正解です。
これらの属性に関係なく、すべての JavaScript はパーサーをブロックします。
もう一度お試しください。
同期 JavaScript は、DOM を変更する可能性があるため、パーサーがその JavaScript に到達したときに実行する必要があります。
正解です。

次は: リソースの読み込みを最適化する

このモジュールでは、ブラウザがウェブページをレンダリングする仕組みの理論の一部、特にページの初期レンダリングを完了するために必要なものについて説明しました。次のモジュールでは、リソースの読み込みを最適化する方法を学習して、このレンダリング パスを最適化する方法について説明します。