モーダルウィンドウ 実装解説|Modal Window CSS & JS Guide

モーダルウィンドウ デザイン見本

ボタンクリックで画面中央にオーバーレイ表示するモーダルウィンドウの実装解説。自前で組む瞬時切り替え・フェードアニメーションに加え、標準の dialog 要素を使う方法まで3パターンのコピペ用コードを掲載。
HTML・CSS・JSコードプレビューツール にて実装確認ができます。

まとめ記事 モーダルウィンドウは「ボタンでメッセージを表示する」5つの方法のひとつです ダイアログ・アコーディオン・ポップアップ・トースト通知との違いと使い分けを、比較表つきでまとめています。

① 基本の開閉 — display プロパティで瞬時に切り替え

ダミーテキスト/ダミーテキスト/ダミーテキスト/ダミーテキスト/ダミーテキスト

HTML
<div id="modal-btn-container">
  <button id="modal-btn">モーダルウィンドウ表示</button>
</div>
<div id="mask"></div>
<div id="modal">
  <p>ダミーテキスト/ダミーテキスト/ダミーテキスト</p>
  <div id="close-btn-container">
    <button id="close-btn">閉じる</button>
  </div>
</div>
CSS
#modal-btn-container {
  display: flex;
  justify-content: center;
}

#modal-btn {
  width: 80%;
  max-width: 240px;
  height: 48px;
  border-radius: 8px;
  background-color: skyblue;
  border: none;
  color: white;
  cursor: pointer;
}

#modal-btn:hover {
  opacity: 0.7;
}

#mask {
  display: none;
}

#mask.appear {
  display: block;
  background: rgba(0, 0, 0, 0.7);
  position: fixed;
  top: 0;
  bottom: 0;
  right: 0;
  left: 0;
  z-index: 1;
}

#modal {
  display: none;
}

#modal.appear {
  display: block;
  background: #fff;
  width: 50%;
  padding: 24px;
  border-radius: 4px;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 2;
}

@media (max-width: 768px) {
  #modal.appear {
    width: 75%;
  }
}

#close-btn-container {
  display: flex;
  justify-content: flex-end;
}

#close-btn {
  border-radius: 8px;
  padding: 8px 16px;
  cursor: pointer;
}
JS
var mask = document.querySelector('#mask');
var modal = document.querySelector('#modal');
var modalBtn = document.querySelector('#modal-btn');
var closeBtn = document.querySelector('#close-btn');

modalBtn.addEventListener('click', function() {
  mask.classList.add('appear');
  modal.classList.add('appear');
});

mask.addEventListener('click', function() {
  mask.classList.remove('appear');
  modal.classList.remove('appear');
});

closeBtn.addEventListener('click', function() {
  mask.classList.remove('appear');
  modal.classList.remove('appear');
});
classList + display: none によるオン/オフ

#mask と #modal に display: none を指定しておき、.appear クラスが付いた時だけ display: block にします。マスク(半透明背景)は position: fixed で画面全体を覆い、モーダル本体は top: 50%; left: 50%; transform: translate(-50%, -50%); の組み合わせで画面中央に配置します。マスク要素にも click イベントを設定することで、背景クリックでも閉じられるようにしています。

② フェードイン — @keyframes で滑らかに表示

ダミーテキスト/ダミーテキスト/ダミーテキスト/ダミーテキスト/ダミーテキスト

HTML
<div id="modal-btn-container">
  <button id="modal-btn">モーダルウィンドウ表示</button>
</div>
<div id="mask"></div>
<div id="modal">
  <p>ダミーテキスト/ダミーテキスト/ダミーテキスト</p>
  <div id="close-btn-container">
    <button id="close-btn">閉じる</button>
  </div>
</div>
CSS
#modal-btn-container {
  display: flex;
  justify-content: center;
}

#modal-btn {
  width: 80%;
  max-width: 240px;
  height: 48px;
  border-radius: 8px;
  background-color: skyblue;
  border: none;
  color: white;
  cursor: pointer;
}

#modal-btn:hover {
  opacity: 0.7;
}

#mask {
  display: none;
}

#mask.appear {
  display: block;
  background: rgba(0, 0, 0, 0.7);
  position: fixed;
  top: 0;
  bottom: 0;
  right: 0;
  left: 0;
  z-index: 1;
  animation: fadeIn 0.5s ease-out;
}

#modal {
  display: none;
}

#modal.appear {
  display: block;
  background: #fff;
  width: 50%;
  padding: 24px;
  border-radius: 4px;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 2;
  animation: fadeIn 0.5s ease-out;
}

@media (max-width: 768px) {
  #modal.appear {
    width: 75%;
  }
}

#close-btn-container {
  display: flex;
  justify-content: flex-end;
}

#close-btn {
  border-radius: 8px;
  padding: 8px 16px;
  cursor: pointer;
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}
JS
var mask = document.querySelector('#mask');
var modal = document.querySelector('#modal');
var modalBtn = document.querySelector('#modal-btn');
var closeBtn = document.querySelector('#close-btn');

modalBtn.addEventListener('click', function() {
  mask.classList.add('appear');
  modal.classList.add('appear');
});

mask.addEventListener('click', function() {
  mask.classList.remove('appear');
  modal.classList.remove('appear');
});

closeBtn.addEventListener('click', function() {
  mask.classList.remove('appear');
  modal.classList.remove('appear');
});
@keyframes によるフェードアニメーション

@keyframes に名前(fadeIn)を付けて opacity の変化を定義し、.appear クラスが付いた際の display: block と同時に animation プロパティを適用します。from が表示前(opacity: 0)、to が表示後(opacity: 1)の状態です。マスクとモーダル本体の両方に同じアニメーションを設定することで、全体が自然にフワッと現れます。

③ dialog 要素 — 標準機能だけでモーダル表示

標準の dialog 要素です。マスク(背景の暗がり)は ::backdrop で描画され、Escキーでも閉じられます。閉じるボタンはJavaScriptを使わず、form の method=”dialog” で動いています。

HTML
<button id="dlg-open">dialog 要素で表示</button>

<dialog id="my-dlg" class="dlg">
  <p class="dlg-txt">標準の dialog 要素です。</p>
  <form method="dialog" class="dlg-form">
    <button class="dlg-close">閉じる</button>
  </form>
</dialog>
CSS
#dlg-open {
  background: skyblue;
  border: none;
  color: white;
  padding: 12px 24px;
  border-radius: 8px;
  font-size: 14px;
  cursor: pointer;
}

.dlg {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  margin: auto !important;
  width: 50%;
  max-width: 480px;
  height: fit-content;
  max-height: calc(100% - 40px);
  overflow: auto;
  padding: 24px;
  border: none;
  border-radius: 4px;
  background: #fff;
  color: #334155;
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4);
}

.dlg::backdrop {
  background: rgba(0, 0, 0, 0.7);
}

.dlg-txt {
  font-size: 13px;
  line-height: 1.7;
  margin: 0 0 12px;
}

.dlg-form {
  display: flex;
  justify-content: flex-end;
  margin: 0;
}

.dlg-close {
  border-radius: 8px;
  padding: 6px 14px;
  font-size: 13px;
  border: 1px solid #cbd5e1;
  background: #fff;
  cursor: pointer;
}

@media (max-width: 768px) {
  .dlg {
    width: 75%;
  }
}
JS
var dlgOpen = document.getElementById('dlg-open');
var myDlg = document.getElementById('my-dlg');

dlgOpen.addEventListener('click', function() {
  myDlg.showModal();
});
dialog 要素 + showModal()

HTMLに標準で用意されているモーダル用の要素です。①・② ではマスク用のdivを自分で置き、position: fixed で中央に寄せ、z-indexを調整し、閉じる処理を書く必要がありましたが、dialog 要素なら showModal() を呼ぶだけで、画面中央への配置・背景の暗がり・Escキーで閉じる・背面の要素へフォーカスが移らないことまで、まとめてブラウザが引き受けてくれます。JavaScriptが上の3行だけで済んでいるのはそのためです。マスクの色は ::backdrop という専用の擬似要素で指定します。閉じるボタンは form の method=”dialog” を使うとJavaScriptなしで動きます。なお show() で開くとモードレス(背面を操作できる状態)になり、背景の暗がりも付きません。両者は別物なので注意してください。
また、dialog 要素が画面中央に来るのは、ブラウザ標準のスタイルが上下左右を0にしたうえで margin: auto を指定しているからです。上下左右が0で高さが決まっている要素は、上下のマージンが両方 auto のときだけ余白が均等に配分されて中央に来ます。ここでテーマやリセットCSSが margin-bottom などを上書きすると、auto が残った側のマージンが余白をすべて吸収してしまい、ウィンドウが画面の端(下や左上)に寄ります。ブラウザ標準のスタイルはサイト側のCSSに必ず負けるため、上のCSSのように位置指定と margin: auto を自分で書き、テーマが !important を使っている環境ではこちらも !important を付けて確実に上書きしてください。

モーダルウィンドウ 応用編

④ お知らせ表示 — クリックした項目に合わせて内容を切り替え

お知らせ 1

お知らせ1の内容です。クリックした項目に対応したコンテンツをモーダルに表示できます。

お知らせ 2

お知らせ2の内容です。タブメニューのようなUIをモーダルと組み合わせて実現できます。

お知らせ 3

お知らせ3の内容です。1つのモーダルで複数の内容を使い分けられます。

1つのモーダルに複数のコンテンツを用意する

クリックした項目の番号をJavaScriptで判定し、対応するコンテンツブロックだけを表示します。コンテンツは最初からHTMLに書いておき、display: none / display: block で切り替えるのがシンプルです。タブメニューのようなUIをモーダルと組み合わせて実現できます。

⑤ 拡大表示 — サムネイルをクリックして画像を拡大

クリックしたサムネイルを拡大表示する

各サムネイルに固有の識別子を持たせ、クリック時にそれに対応する大きな画像ブロックだけを表示します。実際の画像では img タグの src を書き換える方法も使えます。マスクをクリックすれば閉じる動作も同様に実装できます。


当サイトで公開しているWebデザインやUIの実装例は、一覧として以下記事に纏めています。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次