JavaScriptで動画をモーダルウィンドウで表示する



Webページで動画コンテンツを強調し、ユーザーに視聴してもらいたい場合、画像を強調する際によく活用されるモーダルウィンドウ(ポップアップ)で表示するデザインが有効です。

よくある画像をモーダルウィンドウで表示する方法では、JavaScriptのライブラリ「Lightbox」などを利用することで手軽に実装できますが、Lightboxは動画に対応していません。
jQueryを利用すれば、jQueryプラグインの「modal-video.js」を使うのも1つの方法です。しかし、プラグインを利用してもWebページのデザインや構造に合わないと、反って使いずらいこともあります。
できればWebページに合わせてカスタマイズできるといいので、モーダルウィンドウを実装するJavaScriptを自作するのもいいでしょう。

モーダルウィンドウの動作の流れを考えると、意外と手軽にJavaScriptで自作することができます。
ここではjQueryプラグインを使わず、JavaScriptで動画をモーダルウィンドウで表示する方法についてご紹介します。

動画のモーダルウィンドウを実装する


動画をモーダルウィンドウで実装する方法として、動画コンテンツが1ページに1つの場合と1ページに複数(例えば動画ギャラリーのようなデザイン)ある場合では、JavaScriptのプログラムが少し変わってきます。

Webページのデザインによって変わってくるので、1つの動画の場合と複数の動画の場合と2パターンの実装方法をご紹介します。

1つの動画でモーダルウィンドウを実装する場合


まずは、1つの動画でモーダルウィンドウを実装する場合についてみていきます。
以下、HTMLのサンプルになります。

モーダルウィンドウやその構造のまとまりの親要素を構築し、サムネイルと動画はそれぞれのブロック構造を構築しておきます。
また、動画のブロック構造にはvideo要素と合わせて、モーダルウィンドウを閉じるためのボタン(video-close)の要素も構築します。
動画コンテンツが1ページに1つの場合は、video要素に「videoPlayer」をidとして付与します。

HTML

<div class="modal-window-conts">
  <div class="modal-window-item">
    <div class="thumb">
      <img src="images/thumb-sample01.png" alt="動画">
    </div>
    <div class="video-conts">
      <div class="video-wrap">
        <video id="videoPlayer" controls>
          <source src="video/sample01.mp4" tyle="video/mp4">
        </video>
        <button class="video-close">✖️</button>
      </div>
    </div>
  </div>
</div>



続いてはCSS。

video-contsの要素にはモーダルウィンドウとして表示するための配置や背景色、その他、Flexboxで子要素のvideo要素の配置に関するスタイルを適用させます。そして最初は「visibility: hidden;」や「opacity: 0;」で非表示にしておきます。
class「active」が付与された時に、「visibility: visible;」「opacity: 1;」で表示するようにします。
またvideo-contsの要素には、モーダルウィンドウが他のコンテンツよりも重ね順が上になるように、z-indexプロパティを指定しておきます。

CSS

.modal-window-conts {
  display: flex;
  justify-content: center;
}

/*/// サムネイル画像 ///*/
.modal-window-item .thumb {
  max-width: 300px;
  cursor: pointer;
}

/*/// video-conts ///*/
.video-conts {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background-color: rgba(0,0,0,.7);
  visibility: hidden; /* 非表示にしておく */
  opacity: 0; /* 非表示にしておく */
  transition: all .3s;
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1;
}

/*/// video-conts(active) ///*/
.video-conts.active {
  visibility: visible;
  opacity: 1;
  padding: 20px;
}

#videoPlayer {
  max-width: 1000px;
  width: 100%;
}

/*/// Close Button ///*/
.video-wrap {
  position: relative;
}

.video-close {
  position: absolute;
  top: -20px;
  right: -20px;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid #000;
  cursor: pointer;
}


動画コンテンツ(#videoPlayer)は、レスポンシブWebデザインに対応するようにパーセント指定(100%)、閉じるボタン(.video-close)のボタンサイズや配置に合わせて、video-contsにpadding(padding: 20px;)を指定しておくと表示領域に収めることができます。

最後にJavaScript。
サムネイルやvideo要素、Closeボタンを取得して変数に格納しておき、サムネイルがクリックされたらvideoのコンテンツにクラスを付与して表示させるといったシンプルな処理を行います。

JavaScript

const videoPlayer = document.getElementById('videoPlayer');
const thumb = document.querySelector('.thumb');
const videoConts = document.querySelector('.video-conts');
const videoClose = document.querySelector('.video-close');

function windowOpen() {
  // 動画コンテンツを表示
  videoConts.classList.add('active');
}

function windowClose() {
  // 動画コンテンツを非表示
  videoConts.classList.remove('active');

  // 動画を停止し、時間をリセット
  if (videoPlayer) {
    videoPlayer.pause();
    videoPlayer.currentTime = 0;
  }
}

// ボタンにイベントリスナーを追加
thumb.addEventListener('click', windowOpen);
videoClose.addEventListener('click', windowClose);


クリックのイベント処理は、addEventListenerで「windowOpen」や「windowClose」の関数を実行します。

動画のモーダルウィンドウを実装する



クラスを付与した際にCSSでanimationプロパティなどを活用すれば、シンプルなフェード効果だけでなく、様々なアニメーション効果でモーダルウィンドウを実装することができるでしょう。

また、サムネイル画像の準備については、動画ファイルをWebブラウザでGoogle ChromeやMicrosoft Edgeなどで表示して、右クリックから現在表示しているフレームを保存することができるので、映像のフレームを使うのであれば手軽に準備することができます。

複数の動画でモーダルウィンドウを実装する場合


複数の動画でモーダルウィンドウを実装する場合は、クリックしたサムネイルの対象となる動画を認識する必要があるので、JavaScriptのプログラムは少し変わります。

サンプルとして、動画ギャラリーのようなデザインを例に見ていきます。
まずはHTMLから。

1つ1つの動画コンテンツ(modal-window-item)の構造は先ほどと同じですが、video要素には「videoPlayer」をclassとして付与します。

HTML

<div class="modal-window-conts">

  <div class="modal-window-item">
    <div class="thumb">
      <img src="images/thumb-sample01.png" alt="動画">
    </div>
    <div class="video-conts">
      <div class="video-wrap">
        <video class="videoPlayer" controls>
          <source src="video/sample01.mp4" tyle="video/mp4">
        </video>
        <button class="video-close">✖️</button>
      </div>
    </div>
  </div>

  <div class="modal-window-item">
    <div class="thumb">
      <img src="images/thumb-sample02.png" alt="動画">
    </div>
    <div class="video-conts">
      <div class="video-wrap">
        <video class="videoPlayer" controls>
          <source src="video/sample02.mp4" tyle="video/mp4">
        </video>
        <button class="video-close">✖️</button>
      </div>
    </div>
  </div>

  <div class="modal-window-item">
    <div class="thumb">
      <img src="images/thumb-sample03.png" alt="動画">
    </div>
    <div class="video-conts">
      <div class="video-wrap">
        <video class="videoPlayer" controls>
          <source src="video/sample03.mp4" tyle="video/mp4">
        </video>
        <button class="video-close">✖️</button>
      </div>
    </div>
  </div>

</div>



続いてはCSS。
こちらも先程と概ね適用しているスタイルは変わらず、各動画コンテンツをFlexboxで3列並びのレイアウトを組んでいる部分が違うくらいです。

CSS

.modal-window-conts {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  max-width: 900px;
  margin: 1rem auto;
}

.modal-window-item {
  flex-basis: calc(33.33% - 7px);
  flex-grow: 0;
  flex-shrink: 0;
}

/*/// サムネイル画像 ///*/
.modal-window-item .thumb {
  cursor: pointer;
}

/*/// video-conts ///*/
.video-conts {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background-color: rgba(0,0,0,.7);
  visibility: hidden; /* 非表示にしておく */
  opacity: 0; /* 非表示にしておく */
  transition: all .3s;
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1;
}

/*/// video-conts(active) ///*/
.video-conts.active {
  visibility: visible;
  opacity: 1;
  padding: 20px;
}

.videoPlayer {
  max-width: 1000px;
  width: 100%;
}

/*/// Close Button ///*/
.video-wrap {
  position: relative;
}

.video-close {
  position: absolute;
  top: -20px;
  right: -20px;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid #000;
  cursor: pointer;
}



最後にJavaScript。
複数の動画ではquerySelectorAllメソッドforEachメソッドを使って、クリックしたサムネイルに対応する動画をモーダルウィンドウで表示させます。

JavaScript

/*/// Modal Window ///*/
document.querySelectorAll('.modal-window-item .thumb').forEach((thumb, index) => {
  thumb.addEventListener('click', () => {
    const videoPlayer = document.querySelectorAll('.videoPlayer')[index]; // 対応するvideoPlayerを取得
    const videoConts = document.querySelectorAll('.video-conts')[index]; // 対応するvideo-contsを取得

    // 動画コンテンツを表示
    videoConts.classList.add('active');
  });
});

/*/// Close Button ///*/
document.querySelectorAll('.modal-window-item .video-close').forEach((closeButton, index) => {
  closeButton.addEventListener('click', () => {
    const videoPlayer = document.querySelectorAll('.videoPlayer')[index]; // 対応するvideoPlayerを取得
    const videoConts = document.querySelectorAll('.video-conts')[index]; // 対応するvideo-contsを取得

    // 動画コンテンツを非表示
    videoConts.classList.remove('active');

    // 動画を停止し、時間をリセット
    if (videoPlayer) {
      videoPlayer.pause();
      videoPlayer.currentTime = 0;
    }
  });
});



複数の動画からクリックした対象の動画を把握するために、「querySelectorAll」でセレクタに一致する文書のNodeList(配列風オブジェクト)を返し、forEachメソッドの第1引数の「thumb」に渡し、第2引数でindex(それぞれの要素の位置)をforEachの反復処理で取得します。

複数の動画でモーダルウィンドウを実装する

サムネイル画像に再生ボタンを追加する


サムネイル画像は、動画コンテンツをイメージする画像のままですと動画として認識しにくいため、再生ボタンを表示しておくといいでしょう。
サムネイル画像を準備する際に、再生ボタン付きの画像を用意するのは面倒です。ここはCSSで再生ボタンのデザインを作ってサムネイル画像の上にのせるといいでしょう。

HTMLにて、サムネイル画像のコンテンツブロックに再生ボタンの要素を追加します。

HTML

<div class="thumb">
  <img src="images/thumb-sample01.png" alt="動画">
  <div class="play-button"><span class="video-play"></span></div>
</div>



CSSでは、HTMLで追加した要素に再生ボタンのスタイルを適用させます。
中央寄せとする際は、positionプロパティで調整します。

CSS

/*/// サムネイル画像 ///*/
.modal-window-item .thumb {
  max-width: 300px;
  cursor: pointer;
  position: relative;
}

.play-button {
  position: absolute;
  top: calc(50% + 0.15rem);
  left: 50%;
  transform: translate(-50%, calc(-50% + 0.075rem));
}

.video-play {
  display: inline-block;
  position: relative;
  width: 1em;
  height: 1em;
  background: rgba(0, 0, 0, 0.4);
  border: 0.3rem solid currentColor;
  border-radius: 50%;
  color: #bbb;
  font-size: 50px;
}

.video-play::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 30%;
  transform: translateY(-50%);
  width: 0px;
  height: 0px;
  border: 0.25em solid transparent;
  border-left: 0.45em solid currentColor;
  box-sizing: border-box;
}



複数の動画を並べて実装する場合も、HTMLでの再生ボタンの要素の追加とCSSでのスタイルの適用はほとんど同じです。
CSSはサムネイル画像のスタイルに「max-width: 300px;」があるかないかの違いくらいです。

CSS

/*/// サムネイル画像 ///*/
.modal-window-item .thumb {
  cursor: pointer;
  position: relative;
}

.play-button {
  position: absolute;
  top: calc(50% + 0.15rem);
  left: 50%;
  transform: translate(-50%, calc(-50% + 0.075rem));
}

.video-play {
  display: inline-block;
  position: relative;
  width: 1em;
  height: 1em;
  background: rgba(0, 0, 0, 0.4);
  border: 0.3rem solid currentColor;
  border-radius: 50%;
  color: #bbb;
  font-size: 50px;
}

.video-play::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 30%;
  transform: translateY(-50%);
  width: 0px;
  height: 0px;
  border: 0.25em solid transparent;
  border-left: 0.45em solid currentColor;
  box-sizing: border-box;
}
サムネイル画像に再生ボタンを追加する



以下、ここまでの流れと動作です。
動画(4分47秒)

最後に


動画は情報量が多いことから効果的に情報を伝えることができるため、Webページに動画コンテンツを活用することが増えているかと思います。
これまでの画像のモーダルウィンドウ表示でもあるように、動画コンテンツでもモーダルウィンドウで表示して強調することで、ユーザーに動画を集中して視聴してもらえるでしょう。

モーダルウィンドウの動作を流れを考えると、jQueryプラグインなどを使わずにJavaScriptで自作することができます。
ぜひ参考にしてください。