画像や <iframe>
要素は、他のタイプのリソースよりも多くの帯域幅を消費することがよくあります。<iframe>
要素の場合、その中のページの読み込みとレンダリングにかなりの処理時間がかかることがあります。
画像の遅延読み込みの場合、初期ビューポート外の画像の読み込みを遅らせると、初期ビューポート内のより重要なリソースの帯域幅の競合を減らすのに役立ちます。ネットワーク接続が悪い場合、これによりページの Largest Contentful Paint(LCP)が改善されることがあります。また、再割り当てされた帯域幅により、LCP 候補の読み込みとレンダリングが速くなる可能性があります。
<iframe>
要素については、遅延読み込みを行うことで、ページの起動時の Interaction to Next Paint(INP)を改善できます。これは、<iframe>
が独自のサブリソースを持つ完全に独立した HTML ドキュメントであるためです。<iframe>
要素は別のプロセスで実行できますが、他のスレッドとプロセスを共有することも珍しくありません。これにより、ユーザー入力に対するページの応答性が低下する状況が発生する可能性があります。
したがって、画面外の画像と <iframe>
要素の読み込みを遅延させることは、追求する価値のある手法であり、パフォーマンスの面で妥当な効果を得るために必要な労力は比較的少ないです。このモジュールでは、ページの重要な起動期間中に、より高速で優れたユーザー エクスペリエンスを実現するために、これら 2 種類の要素を遅延読み込みする方法について説明します。
loading
属性を使用して画像を遅延読み込みする
loading
属性を <img>
要素に追加して、ブラウザに読み込み方法を指示できます。
"eager"
は、最初のビューポートの外にある場合でも、画像をすぐに読み込むようブラウザに指示します。これはloading
属性のデフォルト値でもあります。"lazy"
は、画像が可視ビューポートから設定された距離内に入るまで、画像の読み込みを遅延させます。この距離はブラウザによって異なりますが、多くの場合、ユーザーがスクロールして画像が表示されるまでに画像が読み込まれるように十分な距離に設定されています。
また、<picture>
要素を使用している場合、loading
属性は <picture>
要素自体ではなく、その子要素である <img>
要素に適用する必要があります。これは、<picture>
要素が、異なる画像候補を指す追加の <source>
要素を含むコンテナであり、ブラウザが選択した候補がその子 <img>
要素に直接適用されるためです。
最初のビューポートにある画像を遅延読み込みしない
loading="lazy"
属性は、初期ビューポートの外側に配置されている <img>
要素にのみ追加してください。ただし、ページがレンダリングされる前に、ビューポート内の要素の正確な位置を把握するのは難しい場合があります。ビューポートのサイズ、アスペクト比、デバイスが異なることを考慮する必要があります。
たとえば、デスクトップのビューポートは、モバイル デバイスのビューポートとは大きく異なる場合があります。デスクトップのビューポートでは、より多くの垂直スペースがレンダリングされるため、物理的に小さいデバイスのビューポートには表示されない画像が、最初のビューポートに収まる可能性があります。縦向きで使用されるタブレットでも、かなりの縦方向のスペースが表示されます。デスクトップ デバイスよりも縦方向のスペースが表示される場合もあります。
ただし、loading="lazy"
の適用を避けるべきであることがかなり明確なケースもあります。たとえば、ヒーロー画像や、<img>
要素がファーストビューの上部またはレイアウトの上部に表示される可能性が高い画像ユースケースでは、<img>
要素から loading="lazy"
属性を省略する必要があります。これは、LCP 候補になる可能性が高い画像では特に重要です。
遅延読み込みされる画像は、画像の最終的な位置がビューポート内にあるかどうかを判断するために、ブラウザがレイアウトを完了するまで待つ必要があります。つまり、表示されているビューポート内の <img>
要素に loading="lazy"
属性がある場合、その要素は、プリロード スキャナが未加工のマークアップで検出した直後にフェッチされるのではなく、すべての CSS がダウンロード、解析され、ページに適用された後にのみリクエストされます。
<img>
要素の loading
属性はすべての主要なブラウザでサポートされているため、JavaScript を使用して画像を遅延読み込みする必要はありません。ブラウザがすでに提供している機能を提供するためにページに JavaScript を追加すると、INP など、ページのパフォーマンスの他の側面に影響します。
画像の遅延読み込みのデモ
<iframe>
要素を遅延読み込みする
ビューポートに表示されるまで <iframe>
要素を遅延読み込みすると、データ量を大幅に節約し、トップレベル ページの読み込みに必要な重要なリソースの読み込みを改善できます。また、<iframe>
要素は基本的にトップレベルのドキュメント内に読み込まれる HTML ドキュメント全体であるため、多数のサブリソース(特に JavaScript)を含めることができます。これらのフレーム内のタスクにかなりの処理時間が必要な場合、ページの INP に大きな影響を与える可能性があります。
サードパーティの埋め込みは、<iframe>
要素の一般的なユースケースです。たとえば、埋め込み動画プレーヤーやソーシャル メディアの投稿では <iframe>
要素がよく使用されます。また、多くの場合、大量のサブリソースが必要になるため、トップレベル ページの帯域幅競合が発生する可能性があります。たとえば、YouTube 動画の埋め込みを遅延読み込みすると、ページの初回読み込み時に 500 KiB 以上が節約されます。Facebook の「いいね!」ボタン プラグインを遅延読み込みすると、200 KiB 以上が節約されます。そのほとんどは JavaScript です。
いずれにしても、ページの下部に <iframe>
がある場合は、最初に読み込む必要がないのであれば、遅延読み込みを強く検討してください。そうすることで、ユーザー エクスペリエンスを大幅に改善できます。
<iframe>
要素の loading
属性
<iframe>
要素の loading
属性も、すべての主要ブラウザでサポートされています。loading
属性の値とその動作は、loading
属性を使用する <img>
要素の場合と同じです。
"eager"
がデフォルト値です。ブラウザに<iframe>
要素の HTML とそのサブリソースをすぐに読み込むよう指示します。"lazy"
は、<iframe>
要素の HTML とそのサブリソースの読み込みを、ビューポートから事前に定義された距離内になるまで延期します。
iframe の遅延読み込みのデモ
ファサード
ページ読み込み時に埋め込みをすぐに読み込むのではなく、ユーザー操作に応じてオンデマンドで読み込むことができます。ユーザーが操作するまで画像や他の適切な HTML 要素を表示することで、これを実現できます。ユーザーが要素を操作したら、その要素をサードパーティの埋め込みに置き換えることができます。この手法はファサードと呼ばれます。
ファサードの一般的なユースケースは、動画コンテンツ自体に加えて、多くの追加のサブソース(JavaScript など)を読み込む可能性のあるサードパーティ サービスからの動画埋め込みです。このような場合、動画の自動再生に正当な理由がない限り、動画の埋め込みでは、ユーザーが再生ボタンをクリックして再生前に操作する必要があります。
これは、動画の埋め込みと視覚的に類似した静止画像を表示し、その過程で帯域幅を大幅に節約する絶好の機会です。ユーザーが画像をクリックすると、実際の <iframe>
埋め込みに置き換えられ、サードパーティの <iframe>
要素の HTML とそのサブリソースのダウンロードが開始されます。
ページの初回読み込みを改善できるだけでなく、ユーザーが動画を再生しない場合は、動画の配信に必要なリソースがダウンロードされないというメリットもあります。これは、ユーザーのニーズについて誤った想定をすることなく、ユーザーが実際に望むものだけをダウンロードできるようにする優れたパターンです。
チャット ウィジェットも、ファサード手法の優れたユースケースです。ほとんどのチャット ウィジェットは、ページの読み込みやユーザー入力に対する応答性に悪影響を及ぼす可能性のある大量の JavaScript をダウンロードします。事前読み込みと同様に、読み込み時にコストが発生しますが、チャット ウィジェットの場合、すべてのユーザーがチャット ウィジェットを使用する予定がないわけではありません。
一方、ファサードを使用すると、サードパーティの [チャットを開始] ボタンを偽のボタンに置き換えることができます。ユーザーがポインタを一定時間合わせる、クリックするなど、意味のある操作を行うと、ユーザーが必要としたときに実際の機能的なチャット ウィジェットが所定の位置に表示されます。
ファサードを独自に構築することも可能ですが、YouTube 動画用の lite-youtube-embed
、Vimeo 動画用の lite-vimeo-embed
、チャット ウィジェット用の React Live Chat Loader など、人気の高いサードパーティ向けのオープンソース オプションも用意されています。
JavaScript の遅延読み込みライブラリ
<video>
要素、<video>
要素の poster
画像、CSS の background-image
プロパティで読み込まれる画像、その他のサポートされていない要素を遅延読み込みする必要がある場合は、lazysizes や yall.js などの JavaScript ベースの遅延読み込みソリューションを使用できます。これらのタイプのリソースの遅延読み込みはブラウザレベルの機能ではないためです。
特に、音声トラックのない <video>
要素を自動再生してループさせることは、アニメーション GIF を使用するよりもはるかに効率的な代替手段です。アニメーション GIF は、同等の画質の動画リソースよりも数倍大きくなることがよくあります。それでも、これらの動画は帯域幅の点で大きな影響を与える可能性があるため、遅延読み込みを行うことは、帯域幅の無駄を大幅に削減できる追加の最適化となります。
これらのライブラリのほとんどは、Intersection Observer API を使用して動作します。また、ページの HTML が初回読み込み後に変更された場合は、Mutation Observer API も使用して、要素がユーザーのビューポートに入ったタイミングを認識します。画像が表示されるか、ビューポートに近づくと、JavaScript ライブラリは非標準の属性(多くの場合 data-src
または類似の属性)を src
などの正しい属性に置き換えます。
アニメーション GIF を置き換える動画があり、JavaScript ソリューションで遅延読み込みしたいとします。これは、次のマークアップ パターンで yall.js を使用して実現できます。
<!-- The autoplay, loop, muted, and playsinline attributes are to
ensure the video can autoplay without user intervention. -->
<video class="lazy" autoplay loop muted playsinline width="320" height="480">
<source data-src="video.webm" type="video/webm">
<source data-src="video.mp4" type="video/mp4">
</video>
デフォルトでは、yall.js は "lazy"
クラスのすべての対象となる HTML 要素を監視します。yall.js がページに読み込まれて実行されると、ユーザーが動画をビューポートにスクロールするまで動画は読み込まれません。この時点で、<video>
要素の子 <source>
要素の data-src
属性が src
属性に置き換えられ、動画をダウンロードして自動的に再生を開始するリクエストが送信されます。
理解度テスト
<img>
要素と <iframe>
要素の両方で、loading
属性のデフォルト値は何ですか?
"eager"
"lazy"
JavaScript ベースの遅延読み込みソリューションを使用するのが妥当なのはどのような場合ですか?
<video>
要素のポスター画像を遅延読み込みする場合など、loading
属性がサポートされていないリソースの場合。ファサードが有用な手法となるのはどのような場合ですか?
次のステップ: プリフェッチと事前レンダリング
画像の遅延読み込みと <iframe>
要素を理解したことで、ユーザーのニーズを尊重しながら、ページの読み込みを高速化できるようになりました。ただし、リソースの投機的読み込みが望ましい場合もあります。次のモジュールでは、プリフェッチとプリレンダリングについて学びます。これらの手法を慎重に使用すると、次のページを事前に読み込むことで、そのページへのナビゲーションを大幅に高速化できます。