上毛印刷株式会社

【JavaScript】モーダルウィンドウを開いてvimeoを再生する

【JavaScript】モーダルウィンドウを開いてvimeoを再生する

2024年09月09日
WEBサイト制作
  • #HTML
  • #css
  • #JavaScript
  • #tips

こんにちは!
上毛印刷WEB制作担当のソーヤです。

皆さんはvimeoをご存知でしょうか。
普通動画をWEBサイトに掲載するときはYouTubeにアップロードして、埋め込むという形が一般的だと思います。
ですが、YouTubeだとあまり細かくカスタマイズができません。
一方、vimeoは管理画面上で公開範囲の設定やパスワード保護等の非常に細かいカスタマイズが可能です。
ですので、学会や教育関係などの比較的堅いイメージがあるクライアントに人気があります。

そこで、今回は「モーダルウィンドウ」と「vimeo API」を組み合わせたTipsを紹介します。

実装例が少し特殊なので、デモページを作成しました。
アクセスしてみてください。
デモページはこちら(別タブで開きます)

HTML例

<script src="https://player.vimeo.com/api/player.js"></script>

まずはじめにvimeoのAPIを使うため、上記コードをjsファイルの手前に記述してください。
そうしたら、下記コードを記述してください。

<div class="modal-wrap">
  <div class="modalList-item js-item">
    <a href="javascript:void(0);" class="js-modal">
      <div class="modalButton-img">
        <img src="/cp/wp/wp-content/uploads/2024/09/jomo.jpg" alt="">
      </div>
      <h3>
        ここをクリックしてください。<br>
      </h3>
    </a>
    <div class="modal">
      <div class="modal-container">
        <div class="modal-inner">
          <div class="modal-contents">
            <div class="modal-vimeo">
              <iframe class="js-iframe-target" src="https://player.vimeo.com/video/1006070746"  frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe>
            </div>
            <div class="modal-button-wrap">
              <button class="modal-button" type="button">閉じる</button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div class="modalList-item js-item">
    <a href="javascript:void(0);" class="js-modal">
      <div class="modalButton-img">
        <img src="/cp/wp/wp-content/uploads/2024/09/system.jpg" alt="">
      </div>
      <h3>
        ここをクリックしてください。<br>
      </h3>
    </a>
    <div class="modal">
      <div class="modal-container">
        <div class="modal-inner">
          <div class="modal-contents">
            <div class="modal-vimeo">
              <iframe class="js-iframe-target" src="https://player.vimeo.com/video/438077436"  frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe>
            </div>
            <div class="modal-button-wrap">
              <button class="modal-button" type="button">閉じる</button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

CSS例

.modal-wrap{
  display: flex;
  flex-wrap: wrap;
}
.modalList-item {
  width: 300px;
  margin: 0 0 30px 0;
  padding: 0 8px;
}
.modalList-item .modal-contents {
  max-width: 700px;
}
.modalList-item a {
  display: block;
  position: relative;
  width: 100%;
  height: 100%;
  color: #333;
  background-color: #fff;
  box-shadow: 9px 8px 10px rgba(0, 0, 0, 0.2), 0 0 5px 0 #ffffff, -4px 0 5px 0 #ffffff, -4px -6px 15px #ffffff;
  transition: .4s ease;
}
.modalList-item a:hover {
  transform: scale(1.01);
  box-shadow: 15px 14px 17px rgba(0, 0, 0, 0.2), 0 0 8px 0 #ffffff, -7px 0 8px 0 #ffffff, -7px -10px 26px #ffffff;
  opacity: 0.7;
}
.modalList-item a:hover::after {
  transform: translateX(10px);
}
.modalList-item h3 {
  padding: 20px 10px 40px;
  font-size: 22px;
  font-weight: bold;
  line-height: 1.2;
}
.modalList-item h3 span {
  font-size: 14px;
}
.modalButton-img {
  position: relative;
}
.modalButton-img img {
  width: 100%;
  max-width: 100%;
  margin: 0 0 20px;
  vertical-align: top;
}
.modalInner-img {
  position: relative;
  margin: 0 0 20px;
}
.modalInner-img img {
  width: 100%;
  max-width: 100%;
  margin: 0 0 20px;
  vertical-align: top;
}
.modalInner-img + h3 {
  display: flex;
  -webkit-box-align: end;
  -webkit-align-items: flex-end;
  -ms-flex-align: end;
  align-items: flex-end;
  padding: 0 10px 20px 0;
}
.modalList-item .modal-contents {
    max-width: 700px;
}
.modal {
  display: none;
  z-index: 9999;
  position: fixed;
  top: -10px;
  right: 0;
  bottom: -10px;
  left: 0;
  overflow: hidden;
  overflow-y: auto;
  backface-visibility: hidden;
  background-color: rgba(0, 0, 0, 0.45);
}
.modal-container {
  display: table;
  width: 100%;
  height: 100%;
  padding: 10px 0;
}
.modal-inner {
  display: table-cell;
  padding: 2.7em 2em;
  vertical-align: middle;
}
.modal-contents {
  position: relative;
  max-width: 1300px;
  margin: 0 auto;
  padding: 30px;
  background-color: #fff;
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.2);
  text-justify: inter-ideograph;
}
.modal-button-wrap {
  position: absolute;
  top: 20px;
  right: 20px;
}
.modal-button {
  appearance: none;
  display: inline-block;
  position: relative;
  width: 24px;
  height: 24px;
  border: none;
  outline: none;
  background: transparent;
  line-height: 1;
  text-indent: -9999px;
  vertical-align: middle;
  cursor: pointer;
}
.modal-button::before {
  position: absolute;
  top: -25px;
  left: 57px;
  width: 30px;
  height: 30px;
  border: 5px solid #fff;
  border-radius: 50%;
  background-color: #fff;
  background-image: url(/cp/wp/wp-content/uploads/2024/06/modal_close.png);
  background-position: center center;
  background-repeat: no-repeat;
  background-size: contain;
  content: '';
  cursor: pointer;
}
.modal-vimeo {
    display: block;
    position: relative;
    width: 100%;
    padding-bottom: 56.5%;
}
.modal-vimeo iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

JavaScript例

document.addEventListener('DOMContentLoaded', function() {
  var windowEl = window,
      html = document.documentElement,
      body = document.body,
      scrollbarWidth = window.innerWidth - document.body.scrollWidth,
      touchStartY;

  windowEl.addEventListener('touchstart', function(event) {
    touchStartY = event.changedTouches[0].screenY;
  });
  document.querySelectorAll('.js-modal').forEach(function(modalTrigger) {
    modalTrigger.addEventListener('click', function() {
      var overlay = modalTrigger.nextElementSibling;
      var player = new Vimeo.Player(overlay.querySelector('.js-iframe-target'));
      windowEl.addEventListener('touchmove', touchMoveHandler, { passive: false });
      html.style.overflow = 'hidden';
      body.style.overflow = 'hidden';
      if (scrollbarWidth) {
        html.style.paddingRight = scrollbarWidth + 'px';
      }
      overlay.style.display = 'block';
      overlay.style.opacity = 1;
      overlay.style.transition = 'opacity 0.3s';
      player.play();
      var touchMoveHandler = function(event) {
        var currentY = event.changedTouches[0].screenY,
            height = overlay.offsetHeight,
            isTop = touchStartY <= currentY && overlay.scrollTop === 0, isBottom = touchStartY >= currentY && overlay.scrollHeight - overlay.scrollTop === height;
        if (isTop || isBottom) {
          event.preventDefault();
        }
      };
      var closeModal = function() {
        body.style.removeProperty('overflow');
        html.style.removeProperty('overflow');
        html.style.removeProperty('padding-right');
        windowEl.removeEventListener('touchmove', touchMoveHandler);
        overlay.style.transition = 'opacity 0.3s';
        overlay.style.opacity = 0;
        setTimeout(function() {
          overlay.scrollTop = 0;
          overlay.style.display = 'none';
          overlay.style.removeProperty('style');
          html.style.removeProperty('style');
        }, 300);
        player.pause();
      };
      overlay.addEventListener('click', function(event) {
        if (!event.target.closest('.modal-contents')) {
          closeModal();
        }
      });
      overlay.querySelector('.modal-button').addEventListener('click', closeModal);
    });
  });
});

まとめ

今回もjQueryではなく、Vanilla.jsで実装してみました。

コピペしてガンガン使ってください!

WEB制作担当ソーヤ

ソーヤ

上毛印刷WEB制作担当
前職は東証プライム企業の本社WEB受託チームにてフロントエンドエンジニアを3年経験。


この記事に対するご意見・ご感想・ご質問等ありましたら、
ぜひ下記フォームにてお送りください。

    お名前必須
    メールアドレス必須
    お問い合わせ内容必須
    PAGE TOP