上毛印刷株式会社

【JavaScript】クリックしたらモーダルウィンドウで詳細情報を表示する

【JavaScript】クリックしたらモーダルウィンドウで詳細情報を表示する

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

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

今回は使用頻度が高い「モーダルウィンドウ」の実装方法についてご紹介します!
ちなみによく「ポップアップ」と勘違いしている方を見かけますが、
ポップアップ」は、現在開いているウィンドウとは違う、別ウィンドウで表示されるコンテンツを指します。
モーダルウィンドウ」は、現在開いているウィンドウにHTML・CSS・JavaScriptで表示されるコンテンツを指します。
全然違うものなので注意してくださいね。

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

HTML例

<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/06/IMG_1669.jpg" alt="">
    </div>
    <h3>
      ここをクリックしてください。<br>
    </h3>
  </a>
  <div class="modal">
    <div class="modal-container">
      <div class="modal-inner">
        <div class="modal-contents">
          <div class="modalInner-img">
            <img src="/cp/wp/wp-content/uploads/2024/06/IMG_1669.jpg" alt="">
          </div>
          <div class="modalInner-item">
            <p>モーダルウィンドウが開きました。<br>ここにコンテンツを入れてください。<br> ネコかわいいですね。</p>
          </div>
          <div class="modal-button-wrap">
            <button class="modal-button" type="button">閉じる</button>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

CSS例

.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;
}

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;
      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';

      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);
      };

      overlay.addEventListener('click', function(event) {
        if (!event.target.closest('.modal-contents')) {
          closeModal();
        }
      });

      overlay.querySelector('.modal-button').addEventListener('click', function() {
        closeModal();
      });
    });
  });
});

まとめ

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

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

WEB制作担当ソーヤ

ソーヤ

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


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

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