YouTubeの動画をPCではモーダル表示!スマホでは一般的な表示で見せたい!もちろんレスポンシブ対応ね

YouTubeの動画をPCではモーダル表示!スマホでは一般的な表示で見せたい!もちろんレスポンシブ対応ね

PC版はオートプレイ有りで、スマホ版はオートプレイ無し

過日、YouTubeに掲載している動画を自分の所でも見せたい(動画の共有で「埋め込みコード」をページに貼り付ける事)という依頼があった。

スマホ向けは全画面表示になるように(通常の埋め込み動画プレーヤーをタップしたときの一般的な挙動という意味)という条件で、これは特にどうこうすることもなく、動画の「埋め込みコード」をページに記載するだけでOKなのだが、PC向けはちょっと条件が付いてきた。

その条件とは、一覧表示されている動画プレーヤーをクリックしたらモーダルウインドウが表示され、そこで動画の再生がはじまる事。さらに一覧に表示されている動画のタイトルなどのテキスト情報も、そのままモーダルウインドウ上に引き続き表示されるように、というもの。

そして大前提として、記事のタイトルにもあるようにページはレスポンシブデザインなわけで、一応【“youtube” “モーダル”】のキーワードで検索したところ、YouTubeの動画をモーダルウインドウで表示できる&レスポンシブデザインには対応しているライブラリは見つけたが、今回の仕様に合致するものではなかった。

ちなみに、見つけたライブラリのは以下のような感じで、これを色々とカスタマイズするのであれば、モーダルウインドウの表示に特化した汎用ライブラリをカスタマイズした方が早いと思い、早々に思考を切り替えた。

  1. スマホでのアクセスにおいても、一覧表示されている動画プレイヤーをタップすると動画はモーダルウインドウでの表示になるが自動再生はされないため、動画を観るためにはもう一度「動画プレーヤー」をタップする必要がある。
  2. (ざっと見た限り)モーダルウインドウ側に任意のテキストを載せる機能がなく、その機能を追加する必要になる。
  3. 動画プレイヤーをクリック(タップ)すると、URLに「#」が付く。

というわけで、HTMLとCSS、JavaScriptを駆使し、無い知恵を絞ってページはなんとか納品できたので、それを元にvestallのネタとして下記のサンプルページを作成してみた。そうそう、この案件にはもう一つ条件があって、更新頻度がそんなに高くないため更新作業は基本コピペでの人力作業。WordPressなどのCMSは介在しない。

サンプルページ

  • sample page 掲載している動画はあくまでもサンプルです。

※以下、重要だと思う(思われる)コードだけ抜き出して解説している。全体のHTMLソースは各自でチェックして欲しい。

HTML

以下の部分が1パッケージになっており、YouTubeの埋め込みコードと動画のタイトル、簡単な説明文などを動画に合わせて適宜変更していくことになる。

<!-- +|///// ///// ▼ ///// /////|+ -->
        <li class="pkg">
          <div class="vdo-base">
            <!-- ※ モーダル呼出部分 ※「href」注意! -->
            <a class="modal-open" href="#modal01" rel="modal:open"></a>
            <div class="vdo-body"><iframe width="560" height="315" src="https://www.youtube.com/embed/nN3BXvRGjBo" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>
          </div>
          <div class="vdo-txt">
            <h3 class="txt-ttl">Kenshi - (Uncut) Launch Trailer Full Length</h3>
            <p class="txt-txt">CaptainDeathbeard /『Kenshi』の公式トレーラー(フルバージョン)</p>
          </div>
        </li>
<!-- +|///// ///// ▲ ///// /////|+ -->

注意点は、HTML上のコメントにも記載しているように「href」部分

            <!-- ※ モーダル呼出部分 ※「href」注意! -->
            <a class="modal-open" href="#modal01" rel="modal:open"></a>

#modal01にある2桁の数字は、ユニークな番号であるため他の動画と被るのはNG。尚、JavaScriptの所でも触れるが、この番号は2桁の数字で他と被ってなければ連番でなくてもOK。

そして、この<a>タグを動画プレーヤー領域に覆い被せる事により、モーダルウインドウを呼び出すクリック領域とし、既に表示されている動画プレーヤーの中でこぢんまりと動画が再生される事を防いでいる。

ところで、YouTubeの動画には追加できる様々なパラメータがあり、納品案件では再生終了後、関連動画を表示しない「rel=0というパラメータが入っていたが、このサンプルページではプレーンな埋め込みコードのままにしておく。

CSS

今回、基本CSSとして「Reboot.css」を導入し、全てインライン化している。

CSSのリセットというかリブート

サンプルページの112行目の「.modal-open」が、先に述べたモーダルウインドウを呼び出すクリック領域を設定する部分になる。

.modal-open {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 6;
}

さらに、198行目でこの「.modal-open」をdisplay: none;としているので、ブラウザの横幅が768px以下では、このクリック領域が表示されない = モーダルウインドウが表示されない仕様にしている。
※768pxというのは任意に決めてもらって結構。

  .modal-open {
    display: none;
  }

120~133行目までは、YouTube動画のプレーヤーをレスポンシブデザインに対応させるためのCSS。まぁググればいくらでも出てくる有名な方法なので、解説は必要ないでしょうw

.vdo-body {
  max-width: 100%;
  height: auto;
  padding-bottom: 56.25%;
  position: relative;
  overflow: hidden;
}
.vdo-body iframe {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
}

140~145行目は、モーダルウインドウのためのライブラリである「jQuery Modal」付属のCSS「jquery.modal.css」(22~25行目まで)の設定を上書きする設定。

.modal {
  background-color: #242424; // 元の色    #fff
  border-radius: 4px;        // 元の数値  8px
  max-width: 1200px;         // 元の数値  500px
  padding: 10px;             // 元の数値  上下15px | 左右30px
}

146~154行目は、モーダルウインドウ上の動画タイトルなどのテキストへの指定。ここも、特に解説は必要ないでしょう。

155~188行目は、モーダルウインドウの「閉じるボタン」の設定。元のCSS「jquery.modal.css」では、JavaScript上で設定した「Close」の文字列をtext-indent: -9999px;で彼方にぶっ飛ばして「×の画像(base64に変換)」を背景に配置し、閉じるボタンとしているのだが、それはあまりにもあまりなので違う表記に変更。
尚、「jquery.modal.css」の当該部分はインライン化する際に削除。

.modal a.close-modal {
  background-color: #000;
  border: 2px solid #242424;
  border-radius: 50%;
  display: block;
  width: 26px;
  height: 26px;
  padding: 30px 30px 0 0;
  overflow: hidden;
  position: absolute;
  top: -13px;
  right: -13px;
}
.modal a.close-modal:hover {
  background-color: #424242;
}
.modal a.close-modal::before,
.modal a.close-modal::after {
  background-color: #999;
  content: '';
  display: block;
  width: 2px;
  height: 24px;
  margin-left: -1px;
  position: absolute;
  top: 3px;
  left: 50%;
}
.modal a.close-modal::before {
  transform: rotate(-45deg);
}
.modal a.close-modal::after {
  transform: rotate(45deg);
}

192行目の@media screen and (max-width: 768px)で、ブラウザの横幅が768px以下の場合の指定を記述しており、193~196行目で、動画の一覧が2列表示だったのを1列表示に変更。

@media screen and (max-width: 768px) {
  .pkg {
    display: block; // 横幅769px以上では  inline-block
    width: 100%;    // 横幅769px以上では  50%
  }
  .modal-open {
    display: none;  // 動画プレーヤー上に覆い被さっているクリック領域を「ナシ」に
  }
}

201~217行目までは、フォントサイズの単位を「rem」から「vw」に上書きする指定。
まぁ、スマホでのフォントサイズの単位はvwの方がいいよね(個人の主観)という理由から。

@media screen and (max-width: 639px) {
  header .txt-ttl {
    font-size: 5.625vw;
  }
  main .block-inner > .txt-ttl {
    font-size: 5vw;
  }
  .pkg .txt-ttl {
    font-size: 5vw;
  }
  .pkg .txt-txt {
    font-size: 4.375vw;
  }
  .copyright p small {
    font-size: 3.75vw;
  }
}

JavaScript

モーダルウインドウのためのライブラリ

ライブラリそのものの設置の方法や解説は省略するが、自身のJavaScriptのスキルが至らないため、このライブラリにコードを4行追記(改変)する必要がある。よって、それが理由でミニフィ(minify)されたものは使用していない。

それでは、index.html下部の328~355行目の<script>部分から説明していこう。

尚、基本事項として使用しているライブラリ「jQuery Modal」では、モーダルウインドウの呼び出しにrel="modal:open"という記述が必要になる。よってHTMLの.modal-open要素は以下のようになる。

<a class="modal-open" href="#modal01" rel="modal:open"></a>

つまり、この部分をクリックするとモーダルウインドウが表示される。よって、通常は予めHTMLファイル上にモーダルウインドウに表示させたい中身を記述しておき、「jquery.modal.css」で設定されている.modalのクラスを付けておくとdisplay: none;が利き、狙い通りの挙動になるわけだが、今回は以下の理由でそれはNG。

  1. モーダルウインドウに表示させる動画の場合、仕様上「自動再生」が不可欠になる。そのため、予め静的にコードを記述しているとIE 11やEdgeではページが読み込まれた時点で、表示されない動画プレイヤーで動画の読み込みと再生が自動ではじまってしまい、動画の数だけ音声が流れっぱなしになる。尚、Chromeの場合、バージョン66から音がミュートされていない動画の自動再生は抑制されているようだ。Firefoxではそうなったりならなかったり…(「おま環」かもw)。
  2. 動画の再生を止めずにモーダルウインドウを閉じてしまうと、動画自体はユーザー側に見えないだけで、ソースコードとしては存在しているため、これまた表示されていない動画プレイヤーの音声だけが流れる事になる。
  3. WordPressなどのCMSを介せず人力で更新するという前提のため、コンテンツを追加する場合のケアレスミスが起きないようにコピペも必要最小限に留める必要がある。よって、使い回せる「部品」は人の手が入らないようにする。

というわけで、クリックをキッカケでモーダルウインドウの中身は都度生成される仕組みにする。

だがその前に、今回使用した「jQuery Modal」では、モーダルウインドウの表示によってブラウザ右横のスクロールバーがなくなり、その分モーダルウインドウ下のコンテンツがそのスクロールバーの横幅分右にずれるという現象が起きる。モーダルウインドウ用のライブラリには、そのあたりも考慮されて作られているものもあるが、これはそうなっていないので、その対策をまず行う。

どうするかというと、ブラウザ個々のスクロールバー幅を計算してその値を「padding-right」としてheader、footer、mainの各要素に付与するわけだ。

  //  スクロールバーの横幅分ずらす
      $('#wrapper').css('width', 'calc(100vw - 100%)');
      var barwidth   = $('#wrapper').css('width');
      $('#wrapper').css('width', '');
      $('header').css('padding-right', barwidth);
      $('footer').css('padding-right', barwidth);
      $('main').css('padding-right', barwidth);

width: calc(100vw - 100%);で、スクロールバーの横幅が算出できるらしい。「barwidth」に横幅の値を収納したら、$('#wrapper').css('width', '');で#wrapperのwidthの値をリセット。後は、barwidthの値をpadding-rightの値として設定している。

ここから本題に入るが、338行目からの記述では正規表現を使いYouTubeの動画に振られる11桁のIDを取得し、「videoid」に収納している。

  //  YouTube 動画ID
      var youtubesrc = $(this).parent().find('iframe').attr('src');
      var videocode  = youtubesrc.match(/^https:\/\/www.youtube.com\/embed\/(.+?)$/);
      var videoid    = videocode[1];

クリックされた.modal-openからYouTubeの埋め込みコードは直接参照できないため、親要素である.vdo-baseに戻り、そこから改めて「iframe」という部分、つまりYouTubeの埋め込みコードを探し、そこにある「src」内の文字列を「videocode」に収納。

次行では、正規表現を使い後々必要となる動画のIDを探す。記述の仕方が正しいかどうかは不明w 動けばいいやwww

最後に、「videocode[1]」で、正規表現でマッチした文字列を「videoid」に収納。ちなみにvideocode[0]とすると、src内の文字列全部となる──。

と、ここまで書いて気づいた。今回の場合はsrcの文字列をそのまま使用しておけばOKだったw 正規表現なんていらんかったんや~www まぁ気を取り直して、ID部分だけを取り出しておくというのも、また別の機会に役立つ知識になるかと…。

そして、モーダルウインドウ上で使用する動画プレイヤーの生成。

  //  モーダル:動画部分
      var modalvideo = '<div class="vdo-base"><div class="vdo-body"><iframe src="https://www.youtube.com/embed/' + videoid + '?autoplay=1" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div></div>';

モーダルウインドウで動画を見せたい場合には、「モーダルウインドウが表示された時 = 動画の再生がはじまる」とならないとユーザビリティ的にマイナスなので、srcに「autoplay=1」というパラメータを付ける。

自動再生が抑制されているバージョン66以降のChromeでも、モーダルウインドウで表示させたYouTubeの動画ではautoplay=1が利く(今回検証で用いたのは、バージョン71:2018年12月現在)。ページを開いたと同時の(音声がミュートされていない動画の)自動再生がNGって感じなのかな?

ちなみに、srcの文字列をそのまま使いたい場合。

  //  モーダル:動画部分
      var modalvideo = '<div class="vdo-base"><div class="vdo-body"><iframe src="' + youtubesrc + '?autoplay=1" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div></div>';

344行目からは、モーダルウインドウ上で使い回すために、動画のタイトルなどを取得。

  //  モーダル:テキスト部分
      var videotxt   = $(this).parents('.pkg').find('.vdo-txt').html();
      var modaltxt   = '<div class="vdo-txt">' + videotxt + '</div>';

クリックされた.modal-openの先祖要素である.pkgまで遡って.vdo-txtを探し、そこに内包されているhtmlコードを丸ごと取得して「videotxt」に収納。

変数「modaltxt」に収納したのは、モーダルウインドウに表示させるテキストになるが、変数「videotxt」に.vdo-txtも含めた部分を丸ごと収納できていれば、この行は必要ないなw

347行目からは、モーダルウインドウのコンテンツ部分を生成する記述。

  //  モーダル表示
      var modalid    = $(this).attr('href');
      var modalidnum = modalid.match(/^#modal(\d{2})$/);
      var modalnum   = modalidnum[1];
      var modalpkg   = '<div id="modal' + modalnum + '" class="modal-window">' + modalvideo + modaltxt + '</div>';
      $('body').append(modalpkg);

modalid」は、クリックされた.modal-openに記載されているhrefの値を収納。そして「modalidnum」から「modalnum」の2行で、正規表現を使ってhrefの値から2桁の数値を取得している。

なぜ数値だけ取り出しているかというと、$(this).attr('href');の値を収納している「modalid」をそのままID名に使おうとした場合、先頭に付いている「#」が邪魔になるためである。よって、「#」を削除した文字列に加工できれば数字だけを取り出す必要もないし、そもそも「#modal(数字2桁)」という形式である必要もない。

その次の「modalpkg」で、YouTubeの動画の埋め込みコードと動画のテキストを合体させて、$('body').append(modalpkg);で、モーダルウインドウのコンテンツ部分を描画してお終い。

最後に、「jQuery Modal」への追記は、jquery.modal.js (Version 0.9.1)の188行目からのブロックにあるcurrent.close();return current.$elm;の間。

  $.modal.close = function(event) {
    if (!$.modal.isActive()) return;
    if (event) event.preventDefault();
    var current = getCurrent();
    current.close();
    return current.$elm;
  };

上記コードがオリジナルで、下記コードが追記したもの(※区切り線は分かりやすいように入れた)。

  $.modal.close = function(event) {
    if (!$.modal.isActive()) return;
    if (event) event.preventDefault();
    var current = getCurrent();
    current.close();
// ***************************************
    $('.modal-window').remove();
    $('header').css('padding-right', '');
    $('footer').css('padding-right', '');
    $('main').css('padding-right', '');
// ***************************************
    return current.$elm;
  };

追記の理由は、この4行がないとモーダルウインドウを閉じた後も動画はHTML上に残ったままで、表示されていない動画プレイヤーの音声だけが延々と流れる事になるし、スクロールバーが表示された後もpadding-rightの指定が生きたままになるからである。

    $('.modal-window').remove();
    $('header').css('padding-right', '');
    $('footer').css('padding-right', '');
    $('main').css('padding-right', '');

ライブラリをいじる必要のない解決方法があったら教えて欲しいw