【永久保存】JavaScriptでモーダルウィンドウの作り方

読者の悩み

  • モーダルウィンドウの作り方がわからない
  • モーダルウィンドウを開いてる時にスクロールしてしまう
  • 複数のモーダルウィンドウの設置方法がわからない

本記事の内容

  • JavaScriptで自作モーダルウィンドウの作り方
  • 複数のモーダルウィンドウはfor文で設置可能
  • モーダルウィンドウを開いてる時、スクロールを停止する方法

モーダルウィンドウを自作で作ってみたいけど、どうしたらいいの?

モーダルウィンドウを自作で作るには、JavaScriptでHTMLにクラスを付けたり、外したりすることで簡単に実装できます。

JavaScriptのライブラリで設置するより、必要な機能だけをJavaScriptで書くことになるので、軽量に設置できますので、ぜひトライしてみてください。

JavaScriptで自作モーダルウィンドウの作り方

それでは、モーダルウィンドウを作っていきましょう。

必要なファイルはこちらです。事前に作っておいてください。

  • index.html
  • styles.css
  • index.js

htmlファイルでパーツを作っていきましょう

まずはベースとなるHTMLファイルを作っていきます。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>js_modal-window</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>

  <section class="sec-blue">
    <div class="btn btn001">
      <a href="#" class="btn__link">
        <span class="btn__text">Modal Open</span>
      </a>
    </div>
  </section>

  <section class="sec-yellow">
    <div class="btn btn002">
      <a href="#" class="btn__link">
        <span class="btn__text">Modal Open</span>
      </a>
    </div>
  </section>

  <section class="sec-green">
    <div class="btn btn003">
      <a href="#" class="btn__link">
        <span class="btn__text">Modal Open</span>
      </a>
    </div>
  </section>
  <script src="index.js"></script>
</body>
</html>

index.htmlファイルにこのような<section>タグを設置しています。

この<section>タグの中にモーダルを出すボタンも作っています。

headタグ内にcssの読込タグと、

<link rel="stylesheet" href="styles.css">

</body>閉じタグの手前にスクリプトの読込タグを設置しておいてください。

<script src="index.js"></script>

次は、index.htmlファイルにモーダル部分のパーツを書いていきます。

下記コードを、<body>タグのすぐ下に追記してください。

<div class="modal-back">
    <div class="modal modal001">
      <p class="modal__text">モーダルのテキストです。モーダルのテキストです。モーダルのテキストです。モーダルのテキストです。モーダルのテキストです。モーダルのテキストです。</p>
    </div>
    <div class="modal modal002">
      <p class="modal__text">モーダル002のテキストです。モーダル002のテキストです。モーダルのテキスト002です。モーダル002のテキストです。モーダル002のテキストです。モーダル002のテキストです。</p>
    </div>
    <div class="modal modal003">
      <p class="modal__text">モーダル003のテキストです。モーダル003のテキストです。モーダル003のテキストです。モーダル003のテキストです。モーダル003のテキストです。モーダル003のテキストです。</p>
    </div>
    
    <div class="close">
      <div class="close__line close__line001"></div>
      <div class="close__line close__line002"></div>
    </div>
  </div>

これで、index.htmlが完成しました。

完成のindex.htmlがこちら。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>js_modal-window</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <div class="modal-back">
    <div class="modal modal001">
      <p class="modal__text">モーダルのテキストです。モーダルのテキストです。モーダルのテキストです。モーダルのテキストです。モーダルのテキストです。モーダルのテキストです。</p>
    </div>
    <div class="modal modal002">
      <p class="modal__text">モーダル002のテキストです。モーダル002のテキストです。モーダルのテキスト002です。モーダル002のテキストです。モーダル002のテキストです。モーダル002のテキストです。</p>
    </div>
    <div class="modal modal003">
      <p class="modal__text">モーダル003のテキストです。モーダル003のテキストです。モーダル003のテキストです。モーダル003のテキストです。モーダル003のテキストです。モーダル003のテキストです。</p>
    </div>
    
    <div class="close">
      <div class="close__line close__line001"></div>
      <div class="close__line close__line002"></div>
    </div>
  </div>

  <section class="sec-blue">
    <div class="btn btn001">
      <a href="#" class="btn__link">
        <span class="btn__text">Modal Open</span>
      </a>
    </div>
  </section>

  <section class="sec-yellow">
    <div class="btn btn002">
      <a href="#" class="btn__link">
        <span class="btn__text">Modal Open</span>
      </a>
    </div>
  </section>

  <section class="sec-green">
    <div class="btn btn003">
      <a href="#" class="btn__link">
        <span class="btn__text">Modal Open</span>
      </a>
    </div>
  </section>
  <script src="index.js"></script>
</body>
</html>

ここでのポイントはモーダルを出すボタンとモーダルのパーツは完全に分離して書いているということです。

モーダルは画面全体を覆うように設置するので、<body>タグの直下に配置することも重要な点です。

意外と、パーツ自体はややこしくないですよね。

必要なのは、モーダルを出すボタンとモーダルがあればOKです。

CSSファイルでスタイリングしていきましょう

それでは、CSSでスタイリングをしていきましょう!

まずはsectionのスタイルと、モーダルを出すボタンのスタイリングをしていきます。

body {
  margin: 0;
  position: relative;
}

.sec-blue {
  display: flex;
  align-items: center;
  background-color: rgb(0, 140, 255, .5);
  height: 800px;
}

.sec-yellow {
  display: flex;
  align-items: center;
  background-color: rgba(244, 244, 11);
  height: 800px;
}

.sec-green {
  display: flex;
  align-items: center;
  background-color: rgb(129, 243, 129, .5);
  height: 800px;
}

/* ボタン */
.btn {
  width: 200px;
  margin-left: 20px;
}

.btn__link {
  display: block;
  font-size: 18px;
  text-align: center;
  background-color: #fff;
  color: #333;
  text-decoration: none;
  border: 2px solid #333;
  border-radius: 5px;
}

.btn__text {
  display: block;
  padding: 7px 5px;
}

各<section>タグには、ページに高さ出すために、height: 800px;を付けています。

<body>タグにposition: relative;を付けているのはモーダルの位置を指定するためです。
この場合、<body>タグが基準位置なので、ページ全体をモーダルで覆うことになります。

次はモーダルをスタイリングしていきます。

こちらのコードをstyles.cssの一番下に追記してください。

/* モーダル */
.modal-back {
  width: 100%;
  height: 100vh;
  background-color: rgba(0,0,0,.6);
  position: fixed;
  top: 0;
  left: 0;
}

.modal {
  background-color: #fff;
  padding: 30px 50px;
  border-radius: 10px;
  border: 4px solid rgb(89, 165, 246);
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%)
}

.modal001 {
  background-color: rgb(202, 215, 242);
  transition: opacity .3s;
}

.modal002 {
  background-color: rgb(244, 244, 160);
  transition: opacity .3s;
}

.modal003 {
  background-color: rgb(145, 247, 145);
  transition: opacity .3s;
}

/* クローズボタン */
.close {
  width: 25px;
  height: 25px;
  position: absolute;
  top: 10%;
  right: 5%;
  cursor: pointer;
}

.close__line {
  width: 4px;
  height: 25px;
  background-color: #fff;
  border-radius: 2px;
}

.close__line001 {
  display: inline-block;
  transform: rotate(45deg);
}

.close__line002 {
  position: absolute;
  top: 0;
  left: 0;
  display: inline-block;
  transform: rotate(-45deg);
}

こちらのスタイルでモーダルのスタイルが完成です。

このような表示になっていればOKです。

styles.cssの全体は今こんな感じです。

body {
  margin: 0;
  position: relative;
}

.sec-blue {
  display: flex;
  align-items: center;
  background-color: rgb(0, 140, 255, .5);
  height: 800px;
}

.sec-yellow {
  display: flex;
  align-items: center;
  background-color: rgba(244, 244, 11);
  height: 800px;
}

.sec-green {
  display: flex;
  align-items: center;
  background-color: rgb(129, 243, 129, .5);
  height: 800px;
}

/* ボタン */
.btn {
  width: 200px;
  margin-left: 20px;
}

.btn__link {
  display: block;
  font-size: 18px;
  text-align: center;
  background-color: #fff;
  color: #333;
  text-decoration: none;
  border: 2px solid #333;
  border-radius: 5px;
}

.btn__text {
  display: block;
  padding: 7px 5px;
}

/* モーダル */
.modal-back {
  width: 100%;
  height: 100vh;
  background-color: rgba(0,0,0,.6);
  position: fixed;
  top: 0;
  left: 0;
}

.modal {
  background-color: #fff;
  padding: 30px 50px;
  border-radius: 10px;
  border: 4px solid rgb(89, 165, 246);
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%)
}

.modal001 {
  background-color: rgb(202, 215, 242);
  transition: opacity .3s;
}

.modal002 {
  background-color: rgb(244, 244, 160);
  transition: opacity .3s;
}

.modal003 {
  background-color: rgb(145, 247, 145);
  transition: opacity .3s;
}

/* クローズボタン */
.close {
  width: 25px;
  height: 25px;
  position: absolute;
  top: 10%;
  right: 5%;
  cursor: pointer;
}

.close__line {
  width: 4px;
  height: 25px;
  background-color: #fff;
  border-radius: 2px;
}

.close__line001 {
  display: inline-block;
  transform: rotate(45deg);
}

.close__line002 {
  position: absolute;
  top: 0;
  left: 0;
  display: inline-block;
  transform: rotate(-45deg);
}

現状、3つのモーダルが画面中央で重なっている状態になってまして、黄緑の部分のモーダルはmodal003のモーダルが一番上に乗っていて、modal003が見えている状態になります。

modal-backはモーダルの背景部分になります。
モーダルの背景部分にpositon: fixed;で表示画面に固定して、height: 100vhで表示画面全体を覆うように設定しました。

一度、この状態でボタンをクリックしてみてください。
モーダルがボタンを覆っているのでクリックできないと思います。

右上の✗マークがモーダルを閉じるためのボタンとなります。かんたんにCSSで作りました。
JavaScriptでクリック出来るようにするので、現状は機能していません。

今表示されているモーダルですが、本来はボタンをクリックしたあと、出現するので、初期状態では消えている必要があります。
なので、次のCSSを追記します。

  • opacity: 0;
  • visibility: hidden;

opacity: 0;で表示を透明にして、visibility: hiddenで表示を消してしまいます。

これを4箇所、.modal-back、.modal001、modal002、modal003に追記していきます。

body {
  margin: 0;
  position: relative;
}

.sec-blue {
  display: flex;
  align-items: center;
  background-color: rgb(0, 140, 255, .5);
  height: 800px;
}

.sec-yellow {
  display: flex;
  align-items: center;
  background-color: rgba(244, 244, 11);
  height: 800px;
}

.sec-green {
  display: flex;
  align-items: center;
  background-color: rgb(129, 243, 129, .5);
  height: 800px;
}

/* ボタン */
.btn {
  width: 200px;
  margin-left: 20px;
}

.btn__link {
  display: block;
  font-size: 18px;
  text-align: center;
  background-color: #fff;
  color: #333;
  text-decoration: none;
  border: 2px solid #333;
  border-radius: 5px;
}

.btn__text {
  display: block;
  padding: 7px 5px;
}

/* モーダル */
.modal-back {
  width: 100%;
  height: 100vh;
  background-color: rgba(0,0,0,.6);
  position: fixed;
  top: 0;
  left: 0;
  opacity: 0; /* ここを追記 */
  visibility: hidden;
}

.modal {
  background-color: #fff;
  padding: 30px 50px;
  border-radius: 10px;
  border: 4px solid rgb(89, 165, 246);
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%)
}

.modal001 {
  background-color: rgb(202, 215, 242);
  transition: opacity .3s;
  opacity: 0; /* ここを追記 */
  visibility: hidden;
}

.modal002 {
  background-color: rgb(244, 244, 160);
  transition: opacity .3s;
  opacity: 0; /* ここを追記 */
  visibility: hidden;
}

.modal003 {
  background-color: rgb(145, 247, 145);
  transition: opacity .3s;
  opacity: 0; /* ここを追記 */
  visibility: hidden;
}

/* クローズボタン */
.close {
  width: 25px;
  height: 25px;
  position: absolute;
  top: 10%;
  right: 5%;
  cursor: pointer;
}

.close__line {
  width: 4px;
  height: 25px;
  background-color: #fff;
  border-radius: 2px;
}

.close__line001 {
  display: inline-block;
  transform: rotate(45deg);
}

.close__line002 {
  position: absolute;
  top: 0;
  left: 0;
  display: inline-block;
  transform: rotate(-45deg);
}

styles.cssはこのような感じになります。

プレビューして、モーダルが消えていればOKです。

ボタンをクリック後のスタイルを付けよう

ボタンをクリックした時にJavaScriptでHTMLにクラスを付けてモーダルを出現させるのですが、出現後のスタイルを先に書いておきます。

こちらのCSSをstyles.cssの最後尾に追記していきましょう。

/* モーダル出現後のスタイル */
.modal-back.open {
  opacity: 1;
  visibility: inherit;
}

.modal001.open {
  opacity: 1;
  visibility: inherit;
}

.modal002.open {
  opacity: 1;
  visibility: inherit;
}

.modal003.open {
  opacity: 1;
  visibility: inherit;
}

modal-back(モーダルの背景)に.openというクラスを付けて、opacity: 1;で透明にしていたのを見えるようにして、visibility: inherit;で要素を消していたのを出現させています。

これで、JavaScriptで、Modal Openボタンをクリックした時に、modal-back、modal001、modal002、modal003、にopenのクラスを付加するとモーダルを出現させることができますね。

現在のstyles.cssはこのようになりました。

ody {
  margin: 0;
  position: relative;
}

.sec-blue {
  display: flex;
  align-items: center;
  background-color: rgb(0, 140, 255, .5);
  height: 800px;
}

.sec-yellow {
  display: flex;
  align-items: center;
  background-color: rgba(244, 244, 11);
  height: 800px;
}

.sec-green {
  display: flex;
  align-items: center;
  background-color: rgb(129, 243, 129, .5);
  height: 800px;
}

/* ボタン */
.btn {
  width: 200px;
  margin-left: 20px;
}

.btn__link {
  display: block;
  font-size: 18px;
  text-align: center;
  background-color: #fff;
  color: #333;
  text-decoration: none;
  border: 2px solid #333;
  border-radius: 5px;
}

.btn__text {
  display: block;
  padding: 7px 5px;
}

/* モーダル */
.modal-back {
  width: 100%;
  height: 100vh;
  background-color: rgba(0,0,0,.6);
  position: fixed;
  top: 0;
  left: 0;
  opacity: 0;
  visibility: hidden;
}

.modal {
  background-color: #fff;
  padding: 30px 50px;
  border-radius: 10px;
  border: 4px solid rgb(89, 165, 246);
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%)
}

.modal001 {
  background-color: rgb(202, 215, 242);
  transition: opacity .3s;
  opacity: 0;
  visibility: hidden;
}

.modal002 {
  background-color: rgb(244, 244, 160);
  transition: opacity .3s;
  opacity: 0;
  visibility: hidden;
}

.modal003 {
  background-color: rgb(145, 247, 145);
  transition: opacity .3s;
  opacity: 0;
  visibility: hidden;
}

/* クローズボタン */
.close {
  width: 25px;
  height: 25px;
  position: absolute;
  top: 10%;
  right: 5%;
  cursor: pointer;
}

.close__line {
  width: 4px;
  height: 25px;
  background-color: #fff;
  border-radius: 2px;
}

.close__line001 {
  display: inline-block;
  transform: rotate(45deg);
}

.close__line002 {
  position: absolute;
  top: 0;
  left: 0;
  display: inline-block;
  transform: rotate(-45deg);
}

/* モーダル出現後のスタイル */
.modal-back.open {
  opacity: 1;
  visibility: inherit;
}

.modal001.open {
  opacity: 1;
  visibility: inherit;
}

.modal002.open {
  opacity: 1;
  visibility: inherit;
}

.modal003.open {
  opacity: 1;
  visibility: inherit;
}

それでは、次はJavaScriptを書いていきましょう。

JavaScriptでボタンをクリックした時にクラスを付加しましょう。

必要なHTML要素を取得しよう

JavaScriptを書いていくのですが、まずやることは、今回必要になってくるHTML要素の取得です。

  • モーダルを出現させるボタン
  • モーダルの背景
  • モーダル
  • ✗ボタンを取得(モーダルを閉じるぼたん)

この4つのHTML要素を取得していきます。

今回、わかりやすくするために、モーダルは3つ用意していますが、モーダルが一つだけ動くようにJavaScriptで書いていきます。

index.jsに書いていきましょう。

'use strict';
{
  // Modal Openボタンを取得
  const btn = document.querySelector('.btn__link');
  console.log(btn);
  // モーダルの背景を取得
  const modalBack = document.querySelector('.modal-back');
  console.log(modalBack);
  // モーダルを取得
  const modal = document.querySelector('.modal');
  console.log(modal);
  // ✕ボタンを取得
  const closeBtn = document.querySelector('.close');
  console.log(closeBtn);
}

各要素querySelectorでクラスを指定して、取得していきます。
querySelectorは1個のHTML要素だけを取得できます。

取得した値はconsole.logでちゃんと取得できているか確認しておきます。

コンソールをチェックするとこのような表示が出ていたらOKです。

もし赤文字でエラーが出ている時は、記入ミスなので、コンソールに表示されているエラーの行数を確認し修正してください。

もし、どうしても解決できないなら、コード比較ツールでチェックしてみましょう。
コード比較ツールデュフフ

無事取得できたら、次はモーダルを出すボタンにイベントを付けていきましょう。

ボタンにイベントを付けていこう

addEventListenerでイベントを付加します。

index.jsに下記を最後尾に追記してください。

// イベントを付加
btn.addEventListener('click', function(e) {
      e.preventDefault();
      modalBack.classList.add('open');
      modal.classList.add('open');
  });

btn.addEventListenerとすることで、btnにイベント機能を追加しますよ。という意味になります。

イベントの種類は’click’にすることで、ボタンをクリックしたら〜する。みたいな動作になります。

クリックしたら何をするか?を関数を指定していきます。

関数のわかりやすい記事はこちら。

function(e)のeは、関数内に書いているe.preventDefault();というように引数でeを指定して、aタグのデフォルトの動作をキャンセルしています。

aタグのデフォルトの動作とは、aタグをクリックすると画面推移するということです。ページが初期化されて、トップに戻ってしまうんですね。
ページの一番上にボタンがあるので、気にならないかもですが…

  • modalBack.classList.add(‘open’);
  • modal.classList.add(‘open’);

このコードは、classList.add(‘open’)とすることで、クリックするとopenのクラスを追加します。ということになります。

さきほどCSSで、openを追加したあとのスタイルも書いていたので、もうモーダルが動くはずです。
確認してみましょう。

どうですかね?このように動いてますでしょうか?

もし動いてないなら、コンソールを開いてエラーが出てないか確認してみましょう。

現状は✗ボタンをクリックしてもモーダルが消えないと思います。
なので次は、モーダルを閉じる機能も設置しておきましょう。

モーダルを閉じる機能を付けよう

index.jsの最後尾に下記を追記していきましょう。

 closeBtn.addEventListener('click', function() {
    modalBack.classList.remove('open');
    modal.classList.remove('open');
  });

✗ボタンにクリックイベントを付けています。

✗ボタンはaタグで作ってないので、e.preventDefault();は無しでOKです。

function(関数)の中で、classList.remove(‘open’)となっていますが、removeでopenクラスを外すことができます。

なので、✗ボタンをクリックすると、openクラスが外れて、モーダルをが消えるということになります。

index.js全体はこのような感じになっていると思います。

'use strict';
{
  // Modal Openボタンを取得
  const btn = document.querySelector('.btn__link');
  console.log(btn);
  // モーダルの背景を取得
  const modalBack = document.querySelector('.modal-back');
  console.log(modalBack);
  // モーダルを取得
  const modal = document.querySelector('.modal');
  console.log(modal);
  // ✕ボタンを取得
  const closeBtn = document.querySelector('.close');
  console.log(closeBtn);

  // イベントを付加
  btn.addEventListener('click', function(e) {
      e.preventDefault();
      modalBack.classList.add('open');
      modal.classList.add('open');

  });

  closeBtn.addEventListener('click', function() {
    modalBack.classList.remove('open');
    modal.classList.remove('open');
  });
}

プレビューを観て観ましょう。

これでモーダルがいい感じで動くようになりましたね。

モーダルを表示している時にスクロールをしてみましょう。
モーダルの背面がスクロールできてしまうと思います。

モーダルが出ている時はスクロールできないようにしたいですよね。

次はこのスクロール禁止の機能を付けていきます。

モーダルウィンドウを開いてる時、スクロールを停止する方法

方法はいくつかあるみたいですが、かんたんな方法を1つ紹介します。

まずはCSSです。

こちらのCSSをstyles.cssの「/* モーダル出現後のスタイル */」のすぐ下に設置してください。

body.open {
  height: 100vh;
  overflow-y: hidden;
}

body要素にopenクラスを付加して、高さを100vh(表示画面の高さ)にして、overflow-y: hidden;ではみ出ている部分を見えないようにしました。

これで、モーダルが出ている時はスクロールできないようになります。

styles.css全体はこのようになります。

body {
  margin: 0;
  position: relative;
}

.sec-blue {
  display: flex;
  align-items: center;
  background-color: rgb(0, 140, 255, .5);
  height: 800px;
}

.sec-yellow {
  display: flex;
  align-items: center;
  background-color: rgba(244, 244, 11);
  height: 800px;
}

.sec-green {
  display: flex;
  align-items: center;
  background-color: rgb(129, 243, 129, .5);
  height: 800px;
}

/* ボタン */
.btn {
  width: 200px;
  margin-left: 20px;
}

.btn__link {
  display: block;
  font-size: 18px;
  text-align: center;
  background-color: #fff;
  color: #333;
  text-decoration: none;
  border: 2px solid #333;
  border-radius: 5px;
}

.btn__text {
  display: block;
  padding: 7px 5px;
}

/* モーダル */
.modal-back {
  width: 100%;
  height: 100vh;
  background-color: rgba(0,0,0,.6);
  position: fixed;
  top: 0;
  left: 0;
  opacity: 0;
  visibility: hidden;
}

.modal {
  background-color: #fff;
  padding: 30px 50px;
  border-radius: 10px;
  border: 4px solid rgb(89, 165, 246);
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%)
}

.modal001 {
  background-color: rgb(202, 215, 242);
  transition: opacity .3s;
  opacity: 0;
  visibility: hidden;
}

.modal002 {
  background-color: rgb(244, 244, 160);
  transition: opacity .3s;
  opacity: 0;
  visibility: hidden;
}

.modal003 {
  background-color: rgb(145, 247, 145);
  transition: opacity .3s;
  opacity: 0;
  visibility: hidden;
}

/* クローズボタン */
.close {
  width: 25px;
  height: 25px;
  position: absolute;
  top: 10%;
  right: 5%;
  cursor: pointer;
}

.close__line {
  width: 4px;
  height: 25px;
  background-color: #fff;
  border-radius: 2px;
}

.close__line001 {
  display: inline-block;
  transform: rotate(45deg);
}

.close__line002 {
  position: absolute;
  top: 0;
  left: 0;
  display: inline-block;
  transform: rotate(-45deg);
}

/* モーダル出現後のスタイル */
body.open {   /* ここを追記 */
  height: 100vh;
  overflow-y: hidden;
}


.modal-back.open {
  opacity: 1;
  visibility: inherit;
}

.modal001.open {
  opacity: 1;
  visibility: inherit;
}

.modal002.open {
  opacity: 1;
  visibility: inherit;
}

.modal003.open {
  opacity: 1;
  visibility: inherit;
}

それでは、モーダルが表示された時に、JavaScriptでbodyタグにopenクラスを付けるように設置します。

まずはbody要素を取得します。

index.jsの「// Modal Openボタンを取得」のすぐ上にこちらのコードを追記してください。

// body要素を取得
  const body = document.getElementsByTagName('body')[0];
  console.log(body);

getElementByTagNameで指定したタグを取得できます。
getElementByTagNameは配列で取得するので、最後に[0]が必要になります。

index.jsはこのようになります。

'use strict';
{
  // body要素を取得
  const body = document.getElementsByTagName('body')[0];
  console.log(body);
  // Modal Openボタンを取得
  const btn = document.querySelector('.btn__link');
  console.log(btn);
  // モーダルの背景を取得
  const modalBack = document.querySelector('.modal-back');
  console.log(modalBack);
  // モーダルを取得
  const modal = document.querySelector('.modal');
  console.log(modal);
  // ✕ボタンを取得
  const closeBtn = document.querySelector('.close');
  console.log(closeBtn);

  // イベントを付加
  btn.addEventListener('click', function(e) {
      e.preventDefault();
      modalBack.classList.add('open');
      modal.classList.add('open');
      

  });

  closeBtn.addEventListener('click', function() {
    modalBack.classList.remove('open');
    modal.classList.remove('open');
  });

}

次は、この取得したbody要素にクラスを付けたり外したり出来るように追記します。

モーダルを出すイベント部分にこちらのコードを追記します。

   body.classList.add('open');

モーダルを消すイベント部分にこちらのコードを追記します。

  body.classList.remove('open');

index.jsの全体はこのようになります。

'use strict';

{
  // body要素を取得
  const body = document.getElementsByTagName('body')[0];
  console.log(body);
  // Modal Openボタンを取得
  const btn = document.querySelector('.btn__link');
  console.log(btn);
  // モーダルの背景を取得
  const modalBack = document.querySelector('.modal-back');
  console.log(modalBack);
  // モーダルを取得
  const modal = document.querySelector('.modal');
  console.log(modal);
  // ✕ボタンを取得
  const closeBtn = document.querySelector('.close');
  console.log(closeBtn);

  // イベントを付加
  btn.addEventListener('click', function(e) {
      e.preventDefault();
      modalBack.classList.add('open');
      modal.classList.add('open');
      body.classList.add('open');  /* ここに追記 */
  });

  closeBtn.addEventListener('click', function() {
    modalBack.classList.remove('open');
    modal.classList.remove('open');
    body.classList.remove('open');  /* ここに追記 */
  });

}

これで、モーダルを出している時に、スクロールは出来ないようになっていると思います。
モーダルを消すと、スクロール出来るようになります。

こちらでモーダルをの機能がすべて完成です。
お疲れさまでした!

今の現状はJavaScriptのコードでは、一つのモーダルしか動かせないです。

Webサイトで一つだけモーダルを設置する予定なら、これで大丈夫ですが、複数設置するなら、JavaScriptを少しいじっていかないといけません。

次はモーダルを複数動かせるようにJavaScriptを変更していきましょう。

複数のモーダルウィンドウはfor文で設置可能

モーダルウィンドウを複数設置するには、複数あるボタンと、モーダルを取得していきます。

HTML取得部分のindex.jsを変更していきます。

btnとmodalの部分のquerySelectorの部分をquerySelectorAllに変更していきます。

// body要素を取得
  const body = document.getElementsByTagName('body')[0];
  console.log(body);
  // Modal Openボタンを取得
  const btn = document.querySelectorAll('.btn__link'); /* ここを変更 */
  console.log(btn);
  // モーダルの背景を取得
  const modalBack = document.querySelector('.modal-back');
  console.log(modalBack);
  // モーダルを取得
  const modal = document.querySelectorAll('.modal'); /* ここを変更 */
  console.log(modal);
  // ✕ボタンを取得
  const closeBtn = document.querySelector('.close');
  console.log(closeBtn);

querySelectorAllは同じクラス名の要素をすべて配列で取得します。

コンソールで確認するとこのようになっていると思います。

このNodeList(3)というのが配列で、中身はそれぞれ3つ入っていることがわかりますね。

一番下のエラーは気にしないでください。これから変更していきます。

配列で取り出せた要素を次はfor文で繰り返し処理をしていきます。

index.jsのモーダルを表示するイベントをfor文で囲んでいきます。

 // イベントを付加
  // モーダルを表示
  for (let i = 0; i < btn.length; i++) { /* for文を追加 */
    // ボタンをクリック
    btn[i].addEventListener('click', function(e) {
      e.preventDefault();
      body.classList.add('open');
      modalBack.classList.add('open');
      modal[i].classList.add('open');  /* modalを[i]で1つずつ取り出す */
    });
  }

for文で囲むとこのようになります。

for文とは、配列の中身の数の分だけ処理を繰り返してくれます。
ボタンの数だけイベントを書いてもいいですが、コード量が膨大になり視認性も悪くなります。for文は短く見やすく書くことができます。

[i]の部分は,0からスタートする数字が入ってきます。なので、今回は3つなので、0、1、2と数字が入ります。

関数の中の「modal[i]」はその数字を利用して、i番目のmodalを取り出しています。
ボタンとモーダルの数が一緒なので、そのまま[i]を利用しています。

index.jsの全体はこのような感じになります。

'use strict';

{
  // body要素を取得
  const body = document.getElementsByTagName('body')[0];
  console.log(body);
  // Modal Openボタンを取得
  const btn = document.querySelectorAll('.btn__link');
  console.log(btn);
  // モーダルの背景を取得
  const modalBack = document.querySelector('.modal-back');
  console.log(modalBack);
  // モーダルを取得
  const modal = document.querySelectorAll('.modal');
  console.log(modal);
  // ✕ボタンを取得
  const closeBtn = document.querySelector('.close');
  console.log(closeBtn);

  // イベントを付加
  // モーダルを表示
  for (let i = 0; i < btn.length; i++) { /* for文を追加 */
    // ボタンをクリック
    btn[i].addEventListener('click', function(e) {
      e.preventDefault();
      body.classList.add('open');
      modalBack.classList.add('open');
      modal[i].classList.add('open');  /* modalを[i]で1つずつ取り出す */
    });
  }
  
  closeBtn.addEventListener('click', function() {
    modalBack.classList.remove('open');
    modal.classList.remove('open');
    body.classList.remove('open');
  });
}

このような感じになります。

次は✗ボタンのイベント部分を変更します。

こちらもfor文を使っています。

  // モーダルを非表示
  for (let i = 0; i < closeBtn.length; i++) { /* for文を追加 */
    closeBtn[i].addEventListener('click', function() {
      body.classList.remove('open');
      modalBack.classList.remove('open');
      modal[i].classList.remove('open');  /* modalを[i]で1つずつ取り出す */
    });
  }

こちらはイベントの関数内で、モーダルの部分をfor文で繰り返しています。

すべてのmodalにopenクラスがあれば、openクラスを外す処理を書いています。

こちらのmodal[i]の[i]はモーダルを表示するイベントのときも使ってますが、関数内の変数はその関数内でしか使えないので、別の関数でもう一度[i]を宣言してもエラーにならないです。

変数の使用範囲をスコープといいます。

スコープの解説はこちらを参考にしてください。

これで、もう一度index.jsをすべて見てみましょう。

'use strict';

{
  // body要素を取得
  const body = document.getElementsByTagName('body')[0];
  console.log(body);
  // Modal Openボタンを取得
  const btn = document.querySelectorAll('.btn__link');
  console.log(btn);
  // モーダルの背景を取得
  const modalBack = document.querySelector('.modal-back');
  console.log(modalBack);
  // モーダルを取得
  const modal = document.querySelectorAll('.modal');
  console.log(modal);
  // ✕ボタンを取得
  const closeBtn = document.querySelectorAll('.close');
  console.log(closeBtn);

  // イベントを付加
  // モーダルを表示
  for (let i = 0; i < btn.length; i++) {
    // ボタンをクリック
    btn[i].addEventListener('click', function(e) {
      e.preventDefault();
      body.classList.add('open');
      modalBack.classList.add('open');
      modal[i].classList.add('open');
    });
  }
 // モーダルを非表示
 for (let i = 0; i < closeBtn.length; i++) {
    closeBtn[i].addEventListener('click', function() {
      body.classList.remove('open');
      modalBack.classList.remove('open');
      modal[i].classList.remove('open');
    });
  }

}

これで、すべてのモーダルが動いていると思います。

このように動いていたらOKです。

これで、複数のモーダルの設置も完成です。

今回の内容でわからない部分があれば、完成のデータをこちらからダウンロードできます。

こちらをもとにCSSでスタイルやアニメーションなどを調整してオリジナルモーダルを作ってみてください。

この度は、最後までお読みいただきまして、ありがとうございました。

もし実装などで上手くいかないことありましたら、下記ボタンからご相談いただけましたらありがたいです。

この記事を書いた人

アバター

トノムラマサシ

masashi
京都を拠点にホームページ制作をしています。WordPress、Shopify、JavaScriptを得意としています。
ホームページ制作や技術的なご相談があれば上のフォームからお問合せください。