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

多くの場合、画像と <iframe> 要素は他のタイプのリソースよりも多くの帯域幅を消費します。<iframe> 要素の場合、その中のページの読み込みとレンダリングにかなりの時間がかかる可能性があります。

画像の遅延読み込みの場合、最初のビューポートの外部にある画像の読み込みを延期すると、最初のビューポート内のより重要なリソースに対する帯域幅の競合を減らすことができます。これにより、ネットワーク接続が不安定な場合にページの Largest Contentful Paint(LCP)を改善でき、帯域幅を再割り当てすることで LCP の候補の読み込みと描画が高速化されます。

<iframe> 要素に関しては、遅延読み込みを行うことで、ページの Interaction to Next Paint(INP)を起動時に改善できます。これは、<iframe> が、独自のサブリソースを持つまったく別の HTML ドキュメントであるためです。<iframe> 要素は別のプロセスで実行可能ですが、他のスレッドとプロセスを共有することは珍しくありません。その場合、ページがユーザー入力に応答しにくくなる可能性があります。

したがって、画面外にある画像と <iframe> 要素の読み込みを延期することは、追求する価値のある手法であり、かなり少ない労力でパフォーマンスの面からメリットを得られます。このモジュールでは、この 2 種類の要素を遅延読み込みして、ページの重要な起動期間中にユーザー エクスペリエンスをより高速にし、改善する方法について説明します。

loading 属性を使用した画像の遅延読み込み

<img> 要素に loading 属性を追加して、読み込み方法をブラウザに伝えることができます。

  • "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 はページの 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 プロパティによって読み込まれた画像、その他のサポートされていない要素の遅延読み込みが必要な場合は、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 は、クラスが "lazy" であるすべての修飾 HTML 要素を監視します。ページで yall.js が読み込まれて実行されると、ユーザーがビューポートにスクロールするまで動画は読み込まれません。この時点で、<video> 要素の子 <source> 要素の data-src 属性が src 属性に切り替えられます。これにより、動画をダウンロードし、自動的に再生を開始するよう求めるリクエストを送信できます。

知識を試す

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

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

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

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

ファサードが便利な手法はどれですか。

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

次の機能: プリフェッチと事前レンダリング

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