画像と <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>
要素にのみ追加する必要があります。ただし、ページがレンダリングされる前に、ビューポート内の要素の正確な位置を把握するのは複雑な場合があります。さまざまなビューポートのサイズ、アスペクト比、デバイスを考慮する必要があります。
たとえば、PC のビューポートは、モバイル デバイスのビューポートとは大きく異なる場合があります。PC のビューポートは、より多くの垂直スペースをレンダリングするため、物理的に小さいデバイスの最初のビューポートには表示されない画像を最初のビューポートに収めることができます。縦向きで使用されるタブレットでも、かなりの縦方向のスペースが表示されます。これは、一部のデスクトップ デバイスよりも多い場合があります。
ただし、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 ライブチャット ローダーなど、一般的なサードパーティ向けのオープンソース オプションもあります。
JavaScript 遅延読み込みライブラリ
<video>
要素、<video>
要素の poster
画像、CSS background-image
プロパティによって読み込まれる画像、またはサポートされていないその他の要素を遅延読み込みする必要がある場合は、JavaScript ベースの遅延読み込みソリューション(lazysizes や yall.js など)を使用できます。これらのタイプのリソースの遅延読み込みはブラウザレベルの機能ではないためです。
特に、音声トラックのない <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 ベースの遅延読み込みソリューションを使用すべき状況はどのような場合ですか?
loading
属性がサポートされていないリソースの場合(アニメーション画像の置き換えや、<video>
要素のポスター画像の遅延読み込みを目的とした自動再生動画など)。ファサードはどのような場合に役立つテクニックですか?
次のステップ: プリフェッチとプリレンダリング
画像と <iframe>
要素の遅延読み込みを理解できたので、ユーザーのニーズを尊重しながら、ページの読み込みを高速化できるようになりました。ただし、リソースの推測読み込みが望ましい場合もあります。次のモジュールでは、プリフェッチとプリレンダリングについて学びます。また、これらの手法を慎重に使用することで、後続のページを事前に読み込み、次のページへの移動を大幅に高速化する方法についても説明します。