画像と <iframe> 要素の遅延読み込み

多くの場合、イメージと <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 の [Like] ボタン プラグインの遅延読み込みでは 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 プロパティによって読み込まれた画像、その他のサポートされていない要素の遅延読み込みが必要な場合は、JavaScript ベースの遅延読み込みソリューション(lazysizesyall.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 は、条件を満たすすべての HTML 要素を "lazy" のクラスで監視します。ページに yall.js が読み込まれて実行されると、ユーザーがビューポートにスクロールするまで動画は読み込まれません。この時点で、<video> 要素の子 <source> 要素の data-src 属性は src 属性に切り替えられます。src 属性は動画のダウンロード リクエストを送信し、自動的に再生を開始します。

理解度テスト

<img> 要素と <iframe> 要素の両方の loading 属性のデフォルト値はどれですか。

"eager"
正解です。
"lazy"
もう一度お試しください。

JavaScript ベースの遅延読み込みソリューションはどのような場合に使用しますか。

遅延読み込みが可能なリソースの場合。
もう一度お試しください。
loading 属性がサポートされていないリソースの場合(アニメーション画像を自動再生する場合や、<video> 要素のポスター画像を遅延読み込みする場合など)。
正解です。

ファサードが便利な手法となるのは、どのような場合ですか。

ユーザーのニーズに関係なく、大量のデータを消費するサードパーティの埋め込み向け。
もう一度お試しください。
読み込みに必要なリソースがかなりの量であるだけでなく、すべてのユーザーが操作できるわけではない可能性が高いサードパーティの埋め込みの場合。
正解です。

次のトピック: プリフェッチと事前レンダリング

画像と <iframe> 要素の遅延読み込みを理解できたところで、ユーザーのニーズに配慮しながら、ページの読み込み速度を上げましょう。ただし、リソースの投機的読み込みが望ましい場合もあります。次のモジュールでは、プリフェッチと事前レンダリングについて説明します。また、これらの技術を慎重に使用することで、前もって読み込むことで後続のページへのナビゲーションを大幅に高速化する方法を学びます。