動画の遅延読み込み

公開日: 2019 年 8 月 16 日

画像要素と同様に、動画の遅延読み込みを行うこともできます。動画は通常 <video> 要素で読み込まれますが、YouTube などの他のサービスでホストされている動画の場合は <iframe> を使用する場合があります(その場合は、遅延読み込みの iframe の記事をご覧ください)。

<video> の遅延読み込み方法は、いくつかの異なるソリューションがあるため、ユースケースによって異なります。

通常、動画の自動再生は避けることが推奨されます。これは、ユーザーが動画をコントロールできるようにするためです。このような場合、動画全体を読み込まないようにするには、<video> 要素に preload 属性を指定するのが最善の方法です。

<video controls preload="none" poster="one-does-not-simply-placeholder.jpg">
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>

上の例では、preload 属性に none の値を使用して、ブラウザが動画データを一切プリロードしないようにしています。poster 属性は、動画の読み込み中にスペースを占有するプレースホルダを <video> 要素に指定します。

ほとんどのブラウザでは、preload はデフォルトで metadata に設定され、動画の一部が Content-Range ヘッダーを使用してプリロードされます。これにより、特にブラウザで Content-Range ヘッダーがサポートされていない場合、必要な量よりも多くのデータがダウンロードされる可能性があります。これがサポートされている場合でも、ブラウザはメタデータがどのバイトに保存されているかを知ることができず、ファイルの先頭に保存されていない可能性があります。したがって、動画の読み込みを回避するには、none を指定して preload="none" を使用することをおすすめします。

onmouseenter 属性(または同等の mouseenter イベント ハンドラ)を使用して、ユーザーが動画にカーソルを合わせたときにメタデータをプリロードするように、さらに拡張することもできます。

<video controls
  preload="none"
  poster="one-does-not-simply-placeholder.jpg"
  onmouseenter="event.target.setAttribute('preload','metadata')">
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>

これにより、ユーザーが動画を再生する際の遅延が短縮されるだけでなく、動画の長さがすぐに表示されます。

動画は LCP の候補として適格とみなされる場合があります。poster 画像は動画よりも読み込みが速いため、LCP の候補となる場合はポスター画像を使用する必要があります。また、fetchpriority 属性値を "high" にしてプリロードする必要があります。

<link rel="preload" href="one-does-not-simply-placeholder.jpg" as="image" fetchpriority="high">
<video controls preload="none"
  poster="one-does-not-simply-placeholder.jpg"
  onmouseenter="event.target.setAttribute('preload','metadata')">
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>

アニメーション GIF の代替の動画の場合

自動再生動画は、GIF スタイルのクイック アニメーションによく使用されます。アニメーション GIF は広く使用されていますが、特にファイルサイズなど、さまざまな点で動画に劣ります。アニメーション GIF は、数メガバイトのデータになることがあります。たいてい、同じような画質の動画ははるかに小さくなります。

アニメーション GIF の代わりに <video> 要素を使用するのは、<img> 要素のように単純ではありません。アニメーション GIF には次の 3 つの特徴があります。

  1. 読み込み時に自動的に再生される。
  2. 継続的にループする(必ずしもそうとは限りません)。
  3. オーディオ トラックがない。

これを <video> 要素を使用して行う場合、以下のようになります。

<video autoplay muted loop playsinline>
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>

autoplaymutedloop の各属性は一目瞭然です。iOS で自動再生するには playsinline が必要です。これで、あらゆるプラットフォームで機能する、GIF の代替としての動画を利用できるようになりました。では、どうしたらそれを遅延読み込みできるでしょうか?まず、次のように <video> マークアップを修正します。

<video class="lazy" autoplay muted loop playsinline width="610" height="254" poster="one-does-not-simply.jpg">
  <source data-src="one-does-not-simply.webm" type="video/webm">
  <source data-src="one-does-not-simply.mp4" type="video/mp4">
</video>

poster 属性が追加されているのに気付くでしょう。これは、動画が遅延読み込みされるまで <video> 要素のスペースに表示されるプレースホルダを指定することができます。<img> の遅延読み込みの例と同様に、各 <source> 要素の data-src 属性に動画の URL を指定します。そこから、Intersection Observer ベースのイメージ遅延読み込みの例に似た JavaScript コードを使用します。

document.addEventListener("DOMContentLoaded", function() {
  var lazyVideos = [].slice.call(document.querySelectorAll("video.lazy"));

  if ("IntersectionObserver" in window) {
    var lazyVideoObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(video) {
        if (video.isIntersecting) {
          for (var source in video.target.children) {
            var videoSource = video.target.children[source];
            if (typeof videoSource.tagName === "string" && videoSource.tagName === "SOURCE") {
              videoSource.src = videoSource.dataset.src;
            }
          }

          video.target.load();
          video.target.classList.remove("lazy");
          lazyVideoObserver.unobserve(video.target);
        }
      });
    });

    lazyVideos.forEach(function(lazyVideo) {
      lazyVideoObserver.observe(lazyVideo);
    });
  }
});

<video> 要素を遅延読み込みする場合は、すべての子 <source> 要素を反復処理し、それらの data-src 属性を src 属性に切り替える必要があります。それが完了したら、要素の load メソッドを呼び出して動画の読み込みをトリガーする必要があります。その後、メディアは autoplay 属性に従って自動的に再生を開始します。

この方法により、アニメーション GIF の動作をエミュレートする動画ソリューションが得られます。これは、アニメーション GIF のように集中的なデータ使用を発生させることなく、そのコンテンツを遅延読み込みすることができます。

遅延読み込みライブラリ

動画を遅延読み込みするには、次のライブラリを使用できます。

  • vanilla-lazyloadlozad.js は、Intersection Observer のみを使用する超軽量のオプションです。そのため非常に高性能ですが、古いブラウザで使用するには polyfill が必要です。
  • yall.js は、Intersection Observer を使用し、イベント ハンドラにフォールバックするライブラリです。data-poster 属性を使用して、動画 poster 画像を遅延読み込みすることもできます。
  • React に特化した遅延読み込みライブラリが必要な場合は、react-lazyload を検討してください。これは Intersection Observer を使用しませんが、React を使ったアプリケーションの開発に慣れている場合には、イメージの遅延読み込みを行う慣れた方法です。

これらの遅延読み込みライブラリは、それぞれドキュメント化されており、さまざまな遅延読み込みのためのマークアップ パターンが豊富にあります。