ページ内に複数設置できるモーダル(ポップアップ)ウィンドウをjQueryで実装してみる(備忘録)

今回はjQueryを用いて、ページ内に複数設置できるモーダル(ポップアップ)ウィンドウをを実装してみる。

利用しやすいように、今回はモーダル(ポップアップ)ウィンドウが1つの場合でも、2つ以上の場合でも使えるよう対応している。

また、モーダル(ポップアップ)ウィンドウの中身が、多くなった場合でもスクロールして中身を確認できるように対応している。

その他、ポップアップの切り替わりは、ボタンを押すとふわっと現れ、モーダル(ポップアップ)ウィンドウ以外の部分や×ボタンを押すとふわっと閉じる仕様になっている。

下記の記事では、JavaScriptのみで対応しているものがあるので参考にしてみてほしい。

参考記事はこちら

デモは下記を参考にしてほしい。

それでは解説に入っていく。

htmlの記述について

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>モーダル(ポップアップ)ウィンドウ</title>
  <link rel="stylesheet" href="../reset.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main>
    <section>
      <div class="ly_inner" id="menu1">
        <h2>menu1</h2>
        <div class="md_textblock">
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <!-- モーダル(ポップアップ)ボタン -->
          <p class="js_modalBtnWrap"><a href="" class="js_modalBtnCont" data-modal-btn="modal01">こちらを<span class="hp_pc">クリック</span><span class="hp_sp">タップ</span></a></p>
          <!-- //モーダル(ポップアップ)ボタン -->
        </div>
        <!-- モーダル(ポップアップ)の内容 -->
        <div class="js_modalWrap" id="modal01">
          <div class="js_modalBG"></div>
          <div class="js_modalContInner">
            <span class="js_modalClose"></span>
            <div class="js_modalCont">
              <p><img src="img_sample01.jpg" alt=""></p>
              <p>テキストテキスト</p>
            </div>
          </div>
        </div>
        <!-- //モーダル(ポップアップ)の内容 -->
      </div>
    </section>
    <section>
      <div class="ly_inner" id="menu2">
        <h2>menu2</h2>
        <div class="md_textblock">
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <!-- モーダル(ポップアップ)ボタン -->
          <p class="js_modalBtnWrap"><a href="" class="js_modalBtnCont" data-modal-btn="modal02">中身が多い場合</a></p>
          <!-- //モーダル(ポップアップ)ボタン -->
        </div>
        <!-- モーダル(ポップアップ)の内容 -->
        <div class="js_modalWrap" id="modal02">
          <div class="js_modalBG"></div>
          <div class="js_modalContInner">
            <span class="js_modalClose"></span>
            <div class="js_modalCont">
              <p><img src="img_sample01.jpg" alt=""></p>
              <p>テキストテキスト</p>
              <p>テキストテキスト</p>
              <p>テキストテキスト</p>
              <p><img src="img_sample01.jpg" alt=""></p>
              <p>テキストテキスト</p>
              <p>テキストテキスト</p>
              <p>テキストテキスト</p>
              <p>テキストテキスト</p>
              <p>テキストテキスト</p>
              <p>テキストテキスト</p>
              <p>テキストテキスト</p>
              <p>テキストテキスト</p>
              <p>テキストテキスト</p>
              <p>テキストテキスト</p>
              <p>テキストテキスト</p>
            </div>
          </div>
        </div>
        <!-- //モーダル(ポップアップ)の内容 -->
      </div>
    </section>
    <section>
      <div class="ly_inner" id="menu3">
        <h2>menu3</h2>
        <div class="md_textblock">
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <!-- モーダル(ポップアップ)ボタン -->
          <p class="js_modalBtnWrap"><a href="" class="js_modalBtnCont" data-modal-btn="modal03">色々入れてみる</a></p>
          <!-- //モーダル(ポップアップ)ボタン -->
        </div>
        <!-- モーダル(ポップアップ)の内容 -->
        <div class="js_modalWrap" id="modal03">
          <div class="js_modalBG"></div>
          <div class="js_modalContInner">
            <span class="js_modalClose"></span>
            <div class="js_modalCont">
              <p>テキストテキスト</p>
              <p>テキストテキスト</p>
              <p>テキストテキスト</p>
              <table>
                <tr>
                  <th>見出し</th>
                  <td>内容が入ります内容が入ります</td>
                </tr>
                <tr>
                  <th>見出し</th>
                  <td>内容が入ります内容が入ります</td>
                </tr>
                <tr>
                  <th>見出し</th>
                  <td>内容が入ります内容が入ります</td>
                </tr>
              </table>
              <p><img src="img_sample01.jpg" alt=""></p>
              <p class="md_linkBtnWrap"><a href="" class="md_linkBtnCont">リンクも設置可</a></p>
            </div>
          </div>
        </div>
        <!-- //モーダル(ポップアップ)の内容 -->
      </div>
    </section>
    <section>
      <div class="ly_inner" id="menu4">
        <h2>menu4</h2>
        <div class="md_textblock">
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
        </div>
      </div>
    </section>
    <section>
      <div class="ly_inner" id="menu5">
        <h2>menu5</h2>
        <div class="md_textblock">
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
          <p>テキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入りますテキストが入ります</p>
        </div>
      </div>
    </section>
  </main>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  <script src="style.js"></script>
</body>
</html>

htmlの記述は冒頭で紹介した参考記事と同様なので、解説は割愛する。

cssの記述について

@charset "utf-8";

/* ==========================
  初期設定
========================== */
*,
*::before,
*::after {
  box-sizing: border-box;
}
img {
  width: 100%;
}

/* ==========================
  モーダル(ポップアップ)
========================== */
.js_modalBtnWrap {
  width: 300px;
  max-width: 100%;
  margin: 0 auto;
  text-align: center;
}
.js_modalBtnCont {
  display: block;
  color: #222;
  background-color: #fff;
  padding: 15px 5px;
  transition: 0.3s;
}
.js_modalBtnCont:hover,
.js_modalBtnCont:focus {
  color: #fff;
  background-color: #222;
}
.js_modalWrap {
  display: none;
  z-index: 1000;
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
}
.js_modalBG {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.6);
}
.js_modalContInner {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translateX(-50%) translateY(-50%);
  width: 720px;
  max-width: 100%;
  background-color: #fff;
  max-height: 600px;
  padding: 40px;
}
.js_modalCont {
  overflow-y: scroll;
  max-height: 520px;
}
.js_modalCont > * + * {
  margin-top: 10px;
}
.js_modalContInner > .js_modalClose + * {
  margin-top: 0;
}
.js_modalClose {
  display: block;
  position: absolute;
  top: 10.5px;
  right: 10.5px;
  width: 20px;
  height: 20px;
  overflow: hidden;
  cursor: pointer;
  z-index: 1001;
}
.js_modalClose::before,
.js_modalClose::after {
  content: "";
  background-color: #222;
  position: absolute;
  top: -5px;
  right: 10px;
  width: 1px;
  height: 30px;
}
.js_modalClose::before {
  transform: rotate(45deg);
}
.js_modalClose::after {
  transform: rotate(-45deg);
}

/* ==========================
  コンテンツの中身
========================== */
.ly_inner {
  width: 100%;
  max-width: 1080px;
  margin: 100px auto;
  padding: 40px;
  background-color: #ccc;
}
.ly_inner h2 {
  font-size: 150%;
  font-weight: bold;
  margin-bottom: 30px;
}
.md_textblock > * + * {
  margin-top: 10px;
}
.md_textblock > * + .js_modalBtnWrap {
  margin-top: 20px;
}
table {
  width: 100%;
}
table th,
table td {
  border: 1px solid #222;
  padding: 10px;
}
table th {
  width: 20%;
  background-color: #ccc;
  white-space: nowrap;
}
.md_linkBtnWrap {
  width: 300px;
  max-width: 100%;
  margin: 10px auto 0;
  text-align: center;
}
.md_linkBtnCont {
  display: block;
  color: #222;
  border: 1px solid #222;
  padding: 15px 5px;
  transition: 0.3s;
}
.md_linkBtnCont:hover,
.md_linkBtnCont:focus {
  color: #fff;
  background-color: #222;
}

/* PC幅に適用 */
@media (min-width: 768px) {
  .hp_sp {
    display: none !important;
  }
}
/* スマホ幅に適用 */
@media (max-width: 767px) {
  .hp_pc {
    display: none !important;
  }
  .js_modalContInner {
    max-height: 400px;
    padding: 20px;
  }
  .js_modalCont {
    max-height: 360px;
  }
  .js_modalClose {
    top: -30px;
  }
  .js_modalClose::before,
  .js_modalClose::after {
    background-color: #fff;
  }
}

cssの記述については、jQuery側でfadeInとfadeOutを使うため、下記のjs_modalWrapというクラスに対して、displayをnoneと設定している。

.js_modalWrap {
  display: none;
  z-index: 1000;
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
}

この他にも、冒頭で紹介した記事では、keyframesを設定していたが、こちらは不要になるので削除している。

JavaScriptの記述について

'use strict';

// モーダル(ポップアップ)
$(function() {
  $('.js_modalBtnCont').on('click', function (e) {
    e.preventDefault();
    let target = $(this).data('modal-btn');
    let modal = document.getElementById(target);
    $(modal).fadeIn();
  });

  $('.js_modalBG, .js_modalClose').on('click', function (e) {
    e.preventDefault();
    $('.js_modalWrap').fadeOut();
  });
});

モーダル(ポップアップ)の表示

ページ上のボタン(js_modalBtnContのクラス)をクリックしたときに、

  1. aリンクが遷移しないために、e.preventDefaultを記述
  2. クリックしたボタンのdataを取得することについて、letでtargetの変数を定義
    例えばページの最初のボタンをクリックすると、一番目data-modal-btnのmodal01が取得できる
  3. 2で取得したdataをIDで取得することについて、letでmodalの変数を定義
    この指定によって、「data-modal-btnのmodal01」と「もともとhtmlに記述されているid→modal01」が結びつけられるようになる。
  4. モーダル(ポップアップ)の内容についているid(modal01〜03)に対して、fadeInが実行され、ふわっとモーダル(ポップアップ)が表示される
    例えばページの最初のボタンをクリックすると、一番目data-modal-btnのmodal01が取得できる

モーダル(ポップアップ)の非表示

あとはどこをクリックしたときに、モーダル(ポップアップ)を非表示にしたいかを考えていけばよい。

今回は、下記の場合に対応している。fadeOutを用いれば閉じることができるのでこれだけで対応できる

  • ×の閉じるボタン
  • モーダル(ポップアップ)以外の要素

以上で実装完了だ。