動画を特定の画面幅以下で読み込まれないようにする

トップページのメインビジュアルに大きく動画を配置して再生する手法は、良く使われるデザイン・演出になりました。

しかし、スマートフォンのようなデバイスでは、動画を再生するためにダウンロードに時間がかかり、パケット通信量も画像に比べて増えてしまうことから、スマートフォンでは動画を再生するのではなく、静止画を表示することもあります。

このとき、どのデバイスでも静止画を表示することになれば簡単なのですが、パソコンは動画を再生して、スマートフォンでは画像を表示するなど、表示するメディアをデバイスに合わせて切り替えるという仕様に決まってしまうと簡単にはいきません。

単純にvideo要素とimg要素をCSSのメディアクエリーで表示・非表示の制御すれば、表面的には仕様に合った実装になります。
この場合、CSSでスタイルをdisplay: noneと指定して要素を非表示にするのですが、要素そのものはHTMLから消えないため、video要素で指定された動画ファイルがダウンロードされてしまいます。
使わない動画をわざわざダウンロードするというのはもったいない話です。

そこで、JavaScriptの出番です

今回は、JavaScriptを使って、動画を表示して再生するときだけ、動画ファイルがダウンロードされるように実装する手順を解説します。

目次

処理の流れ

STEP
即時実行関数式の定義とMediaQueryListオブジェクトを作成する

メソッドを定義してすぐ実行されるように、即時実行関数式(IIFE) を定義します。

そして、画面幅の変動を検知するために、MediaQueryListオブジェクトを生成します

STEP
イベントリスナーを設定する

以下の2つのイベントにリスナーを設定します。

  • HTMLの読み込みと解析が完了したとき
  • メディアクエリーの状態が変化したとき(画面幅が変更されたとき)
STEP
video要素を再生するメソッドを作成する

動画を再生する状況であれば、CSSでvideo要素を表示して、JavaScriptで動画をするメソッドを定義します。

HTMLについて

今回、動画と画像のHTMLは以下のようにしました。

<div class="video-wrap">
  <video id="videoElement" data-src="mv01.mp4" muted autoplay playsinline autoplay>
</div>

<div class="image-wrap">
  <img src="image01.jpg" alt="">
</div>

それぞれの要素について、簡単に説明します。

video要素

<div class="video-wrap">
  <video id="videoElement" data-src="mv01.mp4" muted autoplay playsinline autoplay>
</div>

今回は、動画が自動再生されるようにvideo要素の属性を設定しています。

video要素のsrc属性は、動画ファイルへのパスを設定すると動画ファイルがダウンロードされるため、省略しています。
代わりに動画ファイルへのパスは、カスタムデータ属性のdata-src属性に設定しておきます。

video要素を囲むdiv要素は、CSSのメディアクエリーで表示・非表示を指定するための要素です。

img要素

<div class="image-wrap">
  <img src="image01.jpg" alt="">
</div>

今回は画像の表示・非表示をCSSのみで行います。
video要素を囲むdiv要素に対して、CSSのメディアクエリーで表示・非表示を制御します。

CSSについて

動画と画像を表示を切り替えるCSSは、以下のようにしました。

@media screen and (min-width: 601px) {
  .video-wrap {
    display: block;
  }
  .image-wrap {
    display: none;
  }
}
@media screen and (max-width: 600px) {
  .video-wrap {
    display: none;
  }
  .image-wrap {
    display: block;
  }
}

画面幅が600pxより大きければvideo要素を囲むdiv要素を表示して、画面幅が600px以下だったらimg要素を囲むdiv要素を表示するスタイルにしています。

処理の説明

STEP1  即時実行関数式の定義とMediaQueryListオブジェクトを作成する

即時実行関数式を定義する

今回のJavaScriptは、ページが読み込まれると必ず実行されるメソッドになるので、即時実行関数式(IIFE)で定義します。

// 即時実行関数式で定義する
(function(){
  // ここに処理を書く
})();

これで、今回作成するメソッドが他のJavaScriptに影響しないようにしつつ、メソッドを定義してすぐ実行されるようになります。

MediaQueryListオブジェクトを作成する

ブラウザの画面幅を判別して、動画を再生するか静止画を表示するかを決めるため、MediaQueryList オブジェクトが必要になります。

MediaQueryListmatchMedia()windowオブジェクト上で呼び出して作成します。

(function(){

  // MediaQueryListオブジェクトを生成する
  const mql = window.matchMedia('(min-width: 601px)');

})();

今回は、600pxより大きい画面幅のときに動画を再生するので、メディアクエリー文字列を(min-width: 601px)と設定しました。

これで、ブラウザの画面幅が601px以上であれば、mql.matchesプロパティがtrueに設定されるため、画面幅の状態を判定することに使えます。

STEP2 イベントリスナーを設定する

次に、イベントリスナーを設定します。

今回検知したいのは、「ページの読み込みが完了したとき」と「画面幅が変更されたとき」に発生するイベントになります。

DOMContentLoadedイベントにリスナーを設定する

今回は、画像や動画などの読み込みを待つ必要がないため、HTMLの読み込みと解析が完了したあとで発生するイベントのDOMContentLoadedaddEventListener()メソッドを設定します。

(function(){
  const mql = window.matchMedia('(min-width: 601px)');

  // DOMContentLoadedイベントにリスナーを設定する
  document.addEventListener('DOMContentLoaded', setVideoSrc);

})();

MediaQueryListのchangeイベントにリスナーを設定する

今回の要件は「パソコンでは動画を再生して、スマートフォンでは静止画を表示する」なので、最初にページを読み込んだあとに判定して処理を実行する必要ありません。そのため、不要であればこの部分は省略してください。

画面幅が変わったときに処理が実行されるように、MediaQueryListオブジェクトのchangeイベントに addEventListener()メソッドを設定します。

(function(){
  const mql = window.matchMedia('(min-width: 601px)');

  document.addEventListener('DOMContentLoaded', setVideoSrc);

  // MediaQueryListオブジェクトのchangeイベントにリスナーを設定する
  mql.addEventListener('change', setVideoSrc);
})();

イベントリスナーに無名関数を使わない理由

ちなみにイベントリスナーにメソッドを設定せずに、以下のように無名関数で処理を実行させることもできます。

// イベントリスナーに無名関数を設定する
document.addEventListener('DOMContentLoaded', function(){
  // ここに処理を書く
});

今回はメディアクエリーが変わったときにも同じ処理を実行させたいので、無名関数ではなく新しくメソッドを定義して、それぞれのイベントリスナーから呼び出されるようにします。
こうすることで、変更があっても1箇所だけ直せば良く、効率良くコードを書くことができます。

STEP3 video要素を再生するメソッドを作成する

メソッドを定義する

動画再生を制御するメソッドとして、setVideoSrc()を定義します。

(function(){
  const mql = window.matchMedia('(min-width: 601px)');

  // 動画再生を制御するメソッド
  function setVideoSrc(){
  }

  document.addEventListener('DOMContentLoaded', setVideoSrc);
  mql.addEventListener('change', setVideoSrc);
})();

video要素を取得する

video要素を取得して、変数に入れます。
video要素にはid属性を設定しているので、getElementById()メソッドで取得できます。

function setVideoSrc(){
  // video要素を取得する
  const element = document.getElementById('videoElement');
}

指定したメディアクエリーと一致しているか判定する

指定したメディアクエリー(601px以上)と一致しているか判定します。
判定には、 MediaQueryList オブジェクト mqlmatchesプロパティの値を使います。

function setVideoSrc(){
  const element = document.getElementById('videoElement');

  // 指定したメディアクエリーと一致しているか判定する
  if (mql.matches) {
    // 動画を再生する処理
  }
}

この値がtrueであれば、601px以上の画面幅になっていということなので、動画を再生する処理を実行させます。

video要素のsrc属性に値を設定する

動画ファイルのダウンロードが行われないように、video要素のsrc属性は空にして、ファイルへのパスはカスタムデータ属性のdata-src属性に設定してあります。

この data-src属性の値をsrc属性に設定して、動画ファイルが読み込まれるように準備します。

カスタムデータ属性の値は、datasetプロパティで取得できます。

function setVideoSrc(){
  const element = document.getElementById('videoElement');

  if (mql.matches) {
    // カスタムデータ属性の値をsrc属性に設定する
    element.src = element.dataset.src;
  }
}

video要素にload()メソッドを実行する

video要素のsrc属性に動画ファイルのパスを設定しただけでは、動画が再生されません。
video要素を初期状態にリセットして、動画ファイルの読み込みを開始するためにload()メソッドを実行します。

function setVideoSrc(){
  const element = document.getElementById('videoElement');

  if (mql.matches) {
    element.src = element.dataset.src;

    // video要素をリセットして、動画ファイルの読み込みを開始する
    element.load();
  }
}

load()メソッドは、MDNのHTMLMediaElement.load()で詳しく解説されています。

これで、機能を実装することができました。

完成したコード

完成したJavaScriptのコードは、以下のようになります。

// 即時実行関数式で定義する
(function(){
  // MediaQueryListオブジェクトを生成する
  const mql = window.matchMedia('(min-width: 601px)');

  // 動画再生を制御するメソッド
  function setVideoSrc(){
    // video要素を取得する
    const element = document.getElementById('videoElement');

    if (mql.matches) {
      // カスタムデータ属性の値をsrc属性に設定する
      element.src = element.dataset.src;

      // video要素をリセットして、動画ファイルの読み込みを開始する
      element.load();
    }
  }
  
  // DOMContentLoadedイベントにリスナーを設定する
  document.addEventListener('DOMContentLoaded', setVideoSrc);
  
  // MediaQueryListオブジェクトのchangeイベントにリスナーを設定する
  mql.addEventListener('change', setVideoSrc);
})();

デモ

実際にどんな風に動作するのか、確認するためのデモページを用意しました。
以下のリンクから見ることができます。

https://tech-blog.tomono.jp/demo/switch-according-to-the-situation/

まとめ

今回は、画面幅に合わせて動画再生・静止画像表示を切り替えるようにしましたが、特定の条件で再生する動画を切り替えたり、静止画の方もダウンロードさせないようにsrc属性をJavaScriptで設定するなど、いろいろ応用できると思います。

動画はどうしてもファイル容量が大きいため、ダウンロードに時間がかかったり、デバイスに負荷がかかったり、扱いにまだ困るケースが出てしまいます。

ユーザーによい体験をしてもらうためにも、細かいところまで気を遣って、工夫していきましょう。

よかったらシェアしてね!

この記事を書いた人

Webコーダーとして日々研鑽しています。
最近はJavaScriptで実現できるギミックが増えることに喜びながら、後方互換に悩むのが日課になっています。

目次
閉じる