動画の遅延読み込み

公開日: 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 は、数 MB のデータにまで拡張できます。同様の画質の動画は、はるかに小さい傾向があります。

アニメーション 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 のみを使用する非常に軽量なオプションです。そのため、パフォーマンスは非常に優れていますが、古いブラウザで使用するにはポリフィル化する必要があります。
  • yall.js は、Intersection Observer を使用し、イベント ハンドラにフォールバックするライブラリです。data-poster 属性を使用して、動画の poster 画像を遅延読み込みすることもできます。
  • React 固有の遅延読み込みライブラリが必要な場合は、react-lazyload を検討してください。Intersection Observer は使用しませんが、React でアプリケーションを開発しているユーザーには、画像を遅延読み込みする使い慣れた方法を提供します。

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