【CSS+JS】モーダルウィンドウを表示しその中にYouTube動画を動的に埋め込む

2021年5月27日 13:01

はじめに

動画のサムネイル画像をクリックしてモーダルウィンドウを表示し、その中にYouTube動画を動的に埋め込む方法について説明します。なお、本記事ではYouTube動画を動的に埋め込むまでを範囲とし、埋め込んだ動画の再生制御などは範囲外とします。

実装

サンプル

ふたつのサムネイル画像をそれぞれクリックしてみてください。フルスクリーンのモーダルウィンドウが表示され、その中にそれぞれに対応したYouTube動画が埋め込まれています。モーダルウィンドウの動画以外の場所をクリックするとモーダルウィンドウが閉じます。

HTML

コンテナーの中に動画のサムネイル画像を並べます。各動画のdata-url属性で動画のURLを持たせます。

HTML

<div class="container">
  <div class="js-modal-video-open" data-url="https://www.youtube.com/watch?v=xxxxxxxxxxx">
    <img class="thumbnail" src="x-thumb.jpg" />
  </div>
  <div class="js-modal-video-open" data-url="https://www.youtube.com/watch?v=yyyyyyyyyyy">
    <img class="thumbnail" src="y-thumb.jpg" />
  </div>
  <div id="modal-video" class="close js-modal-video-close">
    <div id="player"></div>
  </div>
</div>

Slim

.container
  .js-modal-video-open[data-url="https://www.youtube.com/watch?v=xxxxxxxxxxx"]
    img.thumbnail[src="x-thumb.jpg"]
  .js-modal-video-open[data-url="https://www.youtube.com/watch?v=yyyyyyyyyyy"]
    img.thumbnail[src="y-thumb.jpg"]
  #modal-video.close.js-modal-video-close
    #player

CSS

まずはCSSの全文を掲載します。

SCSS

.container {
  display: flex;
  .thumbnail {
    cursor: pointer;
    width: 320px;
    height: 180px;
    margin: 0 8px;
  }
  #modal-video {
    cursor: pointer;
    display: flex;
    justify-content: center;
    align-items: center;
    position: fixed;
    z-index: 8;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    background-color: rgba(#000,.75);
    transition: .5s;
    &.close {
      filter: opacity(0);
      visibility: hidden;
    }
    &.open {
      filter: opacity(1);
      visibility: visible;
    }
    iframe {
      width: 64vw;
      height: 36vw;
    }
  }
}

ひとつひとつ分解して説明していきます。

SCSS

  .thumbnail {
    cursor: pointer;
    width: 320px;
    height: 180px;
    margin: 0 8px;
  }

サムネイル画像に適用させるスタイルです。カーソルをポインターにしてクリック可能であることを示します。

SCSS

  #modal-video {
    cursor: pointer;
    display: flex;
    justify-content: center;
    align-items: center;
    position: fixed;
    z-index: 8;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    background-color: rgba(#000,.75);
    transition: .5s;
    &.close {
      filter: opacity(0);
      visibility: hidden;
    }
    &.open {
      filter: opacity(1);
      visibility: visible;
    }
    iframe {
      width: 64vw;
      height: 36vw;
    }
  }

モーダルウィンドウのスタイルです。初期状態はcloseクラスを適用させて不可視状態にしておき、後述するJavaScriptの処理でopenを適用させ可視状態に変化します。iframeタグはそのままYouTube動画のスタイルです。後述するJavaScriptの処理でもサイズ指定することはできますが、動画サイズをレスポンシブに変化させたい場合はCSSで設定する必要があります。

JavaScript

まずはJavaScriptの全文を掲載します。

JavaScript

/**
 * @class ToggleModal
 * @description モーダルウィンドウの表示切替を行い、YouTube動画を動的に埋め込む
 * @argument target 対象のYouTube動画を含む要素
 */
class ToggleModal {
  constructor(target) {
    this.target = target;
    this.videoId = target.dataset.url.slice(-11);
    this.loadIframePlayerAPI();
    this.open();
    this.close();
  }

  /**
   * @method loadIframePlayerAPI
   * @description IFrame Player APIを読み込む
   */
  loadIframePlayerAPI() {
    const tag = document.createElement('script');
    tag.src = 'https://www.youtube.com/iframe_api';
    const firstScriptTag = document.getElementsByTagName('script')[0];
    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
  }

  /**
   * @method onYouTubeIframeAPIReady
   * @description YouTube動画を動的に埋め込む
   */
  onYouTubeIframeAPIReady() {
    let ytPlayer = new YT.Player('player', {
      videoId: this.videoId,
      playerVars: {
        'autoplay': 1,
        'controls': 1
      }
    });
  }

  /**
   * @method remakePlayerElement
   * @description YouTube動画を埋め込む要素を再作成
   */
  remakePlayerElement() {
    const modal = document.querySelector('#modal-video');
    modal.removeChild(modal.firstElementChild);
    let tag = document.createElement('div');
    tag.id = 'player';
    modal.appendChild(tag);
  }

  /**
   * @method open
   * @description モーダルウィンドウを開く
   */
  open() {
    this.target.addEventListener('click', event => {
      this.onYouTubeIframeAPIReady();
      document.querySelector('#modal-video').classList.add('open');
      document.querySelector('#modal-video').classList.remove('close');
    });
  }

  /**
   * @method close
   * @description モーダルウィンドウを閉じる
   */
  close() {
    document.querySelector('.js-modal-video-close').addEventListener('click', event => {
      document.querySelector('#modal-video').classList.add('close');
      document.querySelector('#modal-video').classList.remove('open');
      this.remakePlayerElement();
    });
  }
}

document.addEventListener('DOMContentLoaded', event => {
  document.querySelectorAll('.js-modal-video-open').forEach(element => {
    new ToggleModal(element);
  });
});

ひとつひとつ分解して説明していきます。

JavaScript

/**
 * @class ToggleModal
 * @description モーダルウィンドウの表示切替を行い、YouTube動画を動的に埋め込む
 * @argument target 対象のYouTube動画を含む要素
 */
class ToggleModal {
  constructor(target) {
    this.target = target;
    this.videoId = target.dataset.url.slice(-11);
    this.loadIframePlayerAPI();
    this.open();
    this.close();
  }
}

ToggleModalクラスのコンストラクターでは、対象のYouTube動画を含む要素から動画のURLを取得し、YouTube動画の埋め込みを可能にするIFrame Player APIの読み込みとモーダルウィンドウの開閉イベントのリスナー登録を行います。

JavaScript

  /**
   * @method loadIframePlayerAPI
   * @description IFrame Player APIを読み込む
   */
  loadIframePlayerAPI() {
    const tag = document.createElement('script');
    tag.src = 'https://www.youtube.com/iframe_api';
    const firstScriptTag = document.getElementsByTagName('script')[0];
    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
  }

IFrame Player APIの読み込みを行います。ドキュメントに含まれる最初のscriptタグの前にIFrame Player API用のscriptタグを追加します。

JavaScript

  /**
   * @method open
   * @description モーダルウィンドウを開く
   */
  open() {
    this.target.addEventListener('click', event => {
      this.onYouTubeIframeAPIReady();
      document.querySelector('#modal-video').classList.add('open');
      document.querySelector('#modal-video').classList.remove('close');
    });
  }

  /**
   * @method close
   * @description モーダルウィンドウを閉じる
   */
  close() {
    document.querySelector('.js-modal-video-close').addEventListener('click', event => {
      document.querySelector('#modal-video').classList.add('close');
      document.querySelector('#modal-video').classList.remove('open');
      this.remakePlayerElement();
    });
  }

モーダルウィンドウの開閉イベントのリスナー登録を行います。モーダルウィンドウを開く前にYouTube動画を埋め込む処理を行い、モーダルウィンドウを閉じた後にYouTube動画を埋め込む要素を再作成します。

JavaScript

  /**
   * @method onYouTubeIframeAPIReady
   * @description YouTube動画を動的に埋め込む
   */
  onYouTubeIframeAPIReady() {
    let ytPlayer = new YT.Player('player', {
      videoId: this.videoId,
      playerVars: {
        'autoplay': 1,
        'controls': 1
      }
    });
  }

IFrame Player APIを使ってYouTube動画を埋め込みます。YT.Playerクラスの第1引数(今回はplayer)は埋め込むYouTube動画のIDを指定します。指定したIDの子要素にYouTube動画が追加されるのではなく、指定したIDの要素そのものがYouTube動画になります。つまり、指定したIDの要素はなくなるということです。

YT.Playerクラスの第2引数のハッシュは再生プレイヤーのパラメーターを設定します。

パラメーター 説明
videoId 埋め込むYouTube動画のIDを指定(必須)。
playerVars: { autoplay } 動画を開いたときに自動再生しない場合は0、自動再生する場合(iOSを除く)は1を指定。
playerVars: { controls } 再生プレイヤーのコントローラー(音量やシークバーなど)を表示しない場合は0、表示する場合は1を指定。

設定できるパラメーターについて詳しくは以下の記事を参照してください。


JavaScript

  /**
   * @method remakePlayerElement
   * @description YouTube動画を埋め込む要素を再作成
   */
  remakePlayerElement() {
    const modal = document.querySelector('#modal-video');
    modal.removeChild(modal.firstElementChild);
    let tag = document.createElement('div');
    tag.id = 'player';
    modal.appendChild(tag);
  }

モーダルウィンドウを閉じるときに埋め込んだYouTube動画を要素ごと削除します。そして再びYouTube動画を埋め込むためのIDを持った要素を作成します。

JavaScript

document.addEventListener('DOMContentLoaded', event => {
  document.querySelectorAll('.js-modal-video-open').forEach(element => {
    new ToggleModal(element);
  });
});

最後に、各動画に対して作成したToggleModalクラスを作成すれば完成です。

まとめ

JavaScriptの処理は少し長くなってしまいましたが、YouTube動画を埋め込むための便利なAPIが用意されているので、それを使えば簡単にYouTube動画を埋め込むことができます。

本記事を参考にして実装していただければと思います。

関連記事

【CSS+JS】ウィンドウ内全体にファイルをドラッグ&ドロップしてアップロード
# はじめに ユーザーが選択したファイルをアップロードする必要がある場合、ファイル選択フィールドを設置することはもちろんですが、ファイルをドラッグ&ドロップしてアップロードできるようにもなっていると使い勝手のいいサービスだと言えます。しかし、ドラ [...]
2021年6月2日 15:15
【CSS+JS】テキストを1文字ずつ表示するアニメーションの実装方法
# はじめに モダンなサイトでよく見かける「テキストを1文字ずつ表示するアニメーション」の実装方法を解説します。 # 実装 ## サンプル 繰り返し動作を確認したい場合は右下の「Rerun」ボタンをクリックしてください。 <i [...]
2021年5月20日 13:26
【CSS】CSSだけでMarkdownのコードにファイル名をつける
# はじめに Markdownのコードに、そのコードがどのファイルのものなのかを示すためにファイル名が書いてあるとわかりやすいです。以下はQiitaの記事でコードを書いたときの一例です。 <img data-src="https://i.i [...]
2021年4月6日 14:39
【CSS】カーソルを乗せると流れるようなアニメーションのハンバーガーメニューを作る
# はじめに 今回はハンバーガーメニューにカーソルを乗せると川のように流れるアニメーションを作りたいと思います。 今回の記事は以下の記事をベースにしていますので、まだご覧になっていない方は先にこちらをご覧ください。 <div clas [...]
2020年8月31日 8:54
【CSS】JavaScriptを使わずにハンバーガーメニューを作る
# はじめに 当初はスペースの限られるスマートフォンなどの低解像度デバイス向けサイトにおいてスペースを有効活用するために登場したハンバーガーメニューですが、最近はPCなどの高解像度デバイス向けサイトでも使われているのをよく見かけます。 何よ [...]
2020年8月31日 7:34