JavaScriptでモーダルを実装する – 基礎から学ぶ表示・非表示の仕組み

プログラミング

今回は、JavaScriptを使ってモーダルウィンドウを一から実装する方法を解説します。

モーダルは、画面上に重ねて表示されるウィンドウのことで、Webサイトでよく見かける機能です。会員登録フォーム、確認ダイアログ、お知らせ表示など、様々な場面で使われています。

この記事では、CSSとJavaScriptを使った基本的なモーダルの作り方と、実装する際につまずいたポイントを詳しく解説します。

モーダルとは?

モーダルは、画面上に重ねて表示されるウィンドウのことです。背景が半透明の黒で覆われ、モーダルが表示されている間は他の操作ができなくなります。閉じるまで元の画面に戻れないため、ユーザーに何か重要な情報を伝えたり、確認を取ったりする際に使われます。

よく見る例としては、Webサイトで会員登録ボタンを押すと画面が暗くなって登録フォームが表示される、といったものです。これがモーダルです。

モーダルの用途は、詳細情報の表示、確認ダイアログ、フォーム入力、画像拡大表示、お知らせの表示など多岐にわたります。

完成イメージ

完成イメージ

作るモーダルの完成形です。

ボタンをクリックするとモーダルが表示され、閉じるボタンまたは背景をクリックすると閉じる仕組みです。

モーダル実装の完全なコード

まず、完全なコードを見てから、各部分を詳しく解説します。

HTML (index.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="style.css">
</head>
<body>
    <h1>モーダルの実装</h1>
    <button id="openModal">モーダルを開く</button>
    
    <!-- モーダル -->
    <div id="myModal" class="modal">
        <div class="modalContent">
            <span class="close">&times;</span>
            <h2>モーダルのタイトル</h2>
            <p>ここに内容が入ります。</p>
        </div>
    </div>
    
    <script src="script.js"></script>
</body>
</html>

CSS (style.css)

/* ページ全体のスタイル */
body {
    font-family: Arial, sans-serif;
    padding: 20px;
}

button {
    padding: 10px 20px;
    font-size: 1em;
    cursor: pointer;
    background-color: #4CAF50;
    color: white;
    border: none;
    border-radius: 5px;
}

button:hover {
    background-color: #45a049;
}

/* モーダル全体(背景) */
.modal {
    display: none;  /* 最初は非表示 */
    position: fixed;  /* 画面に固定 */
    z-index: 1000;  /* 最前面に表示 */
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);  /* 半透明の黒背景 */
}

/* モーダルのコンテンツ部分 */
.modalContent {
    background-color: #fff;
    margin: 10% auto;  /* 上から10%、左右中央 */
    padding: 30px;
    border-radius: 10px;
    width: 80%;
    max-width: 600px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
    position: relative;
}

/* 閉じるボタン */
.close {
    color: #aaa;
    float: right;
    font-size: 28px;
    font-weight: bold;
    cursor: pointer;
    line-height: 20px;
}

.close:hover {
    color: #000;
}

JavaScript (script.js)

// 要素を取得
const modal = document.getElementById('myModal');
const openBtn = document.getElementById('openModal');
const closeBtn = document.getElementsByClassName('close')[0];

// モーダルを開く
openBtn.addEventListener('click', () => {
    modal.style.display = 'block';
});

// 閉じるボタンでモーダルを閉じる
closeBtn.addEventListener('click', () => {
    modal.style.display = 'none';
});

// 背景をクリックしてモーダルを閉じる
window.addEventListener('click', (e) => {
    if (e.target == modal) {
        modal.style.display = 'none';
    }
});


モーダルのコード詳細解説

それでは、各部分を詳しく見ていきましょう。

HTMLの構造

モーダルのHTMLは非常にシンプルです。

<!-- モーダル -->
<div id="myModal" class="modal">
    <div class="modalContent">
        <span class="close">&times;</span>
        <h2>モーダルのタイトル</h2>
        <p>ここに内容が入ります。</p>
    </div>
</div>

構造は2階層になっています。外側の modal が画面全体を覆う背景で、内側の modalContent が実際に表示したい内容です。&times; は「×」記号のHTMLエンティティで、閉じるボタンとして使います。

CSSの重要なポイント

モーダルのCSSで特に重要なプロパティを解説します。

display: none

最初は非表示にしておきます。JavaScriptで display: block に変更することで表示します。

.modal {
    display: none;  /* 最初は見えない */
}

JavaScriptから以下のように変更すると表示されます。

modal.style.display = 'block';  /* 表示される */

position: fixed

画面に固定されたまま表示されます。スクロールしても動きません。

.modal {
    position: fixed;  /* 画面に固定 */
}

通常の要素は position: static でスクロールすると一緒に動きますが、モーダルは position: fixed で画面に固定されます。

z-index: 1000

他の要素より前面に表示されます。数字が大きいほど前に来ます。

.modal {
    z-index: 1000;  /* 一番前 */
}

通常のコンテンツは z-index: 1 程度ですが、モーダルは1000にすることで確実に最前面に表示されます。

rgba(0, 0, 0, 0.5)

半透明の黒色を作ります。

.modal {
    background-color: rgba(0, 0, 0, 0.5);
}

rgb(0, 0, 0) は完全な黒ですが、rgba(0, 0, 0, 0.5) は不透明度50%の半透明の黒になります。不透明度の値は、0.0が完全に透明(見えない)、0.5が半透明、1.0が完全に不透明です。

margin: 10% auto

上から10%の位置に配置し、左右は中央揃えにします。

.modalContent {
    margin: 10% auto;
}

10% が上からの位置、auto が左右の自動調整(中央揃え)を意味します。

max-width: 600px

大きな画面でも600pxまでに制限します。

.modalContent {
    width: 80%;
    max-width: 600px;
}

小さい画面(スマホ)では画面の80%、大きい画面(PC)では80%だと大きすぎるので最大600pxに制限します。

JavaScriptの処理

JavaScriptでモーダルの開閉を制御します。

モーダルを開く

openBtn.addEventListener('click', () => {
    modal.style.display = 'block';
});

ボタンをクリックすると、display プロパティを block に変更してモーダルを表示します。

モーダルを閉じる(2つの方法)

モーダルを閉じる方法は2つあります。

方法1: 閉じるボタンをクリック

closeBtn.addEventListener('click', () => {
    modal.style.display = 'none';
});

×ボタンをクリックすると、display プロパティを none に変更してモーダルを非表示にします。

方法2: 背景をクリック

window.addEventListener('click', (e) => {
    if (e.target == modal) {
        modal.style.display = 'none';
    }
});

e.target はクリックされた要素そのものです。e.target == modal は背景部分をクリックしたことを意味し、e.target == modal でない場合はコンテンツ部分をクリックしたことを意味します。

背景だけクリックしたときに閉じる仕組みです。コンテンツ部分をクリックしても閉じないようにするために、この判定が必要です。


モーダルでつまずいたポイント

1. モーダル内をクリックしても閉じてしまう

最初、以下のように書いてしまい、モーダルのどこをクリックしても閉じてしまう問題がありました。

// 間違い
modal.addEventListener('click', () => {
    modal.style.display = 'none';
});

これだと、モーダル内のどこをクリックしても閉じてしまいます。正しくは、e.target でクリックされた要素を判定する必要があります。

// 正解
window.addEventListener('click', (e) => {
    if (e.target == modal) {  // 背景部分だけ
        modal.style.display = 'none';
    }
});

2. getElementsByClassNameの返り値

閉じるボタンが動かない問題がありました。

// 間違い
const closeBtn = document.getElementsByClassName('close');
closeBtn.addEventListener('click', () => {  // エラー!
    modal.style.display = 'none';
});

getElementsByClassName() は配列のようなオブジェクトを返すため、1つ目の要素を取得する必要があります。

// 正解
const closeBtn = document.getElementsByClassName('close')[0];

他の方法としては、getElementById()querySelector() を使う方法もあります。

// 方法2: getElementByIdを使う(推奨)
<span class="close" id="closeBtn">&times;</span>
const closeBtn = document.getElementById('closeBtn');

// 方法3: querySelectorを使う
const closeBtn = document.querySelector('.close');

3. z-indexの設定忘れ

モーダルが他の要素の後ろに隠れてしまう問題がありました。

/*  z-indexがない */
.modal {
    position: fixed;
}

z-index を設定することで、確実に最前面に表示されます。

/*  z-indexを設定 */
.modal {
    position: fixed;
    z-index: 1000;
}

4. position: fixedの指定忘れ

スクロールするとモーダルがズレる問題がありました。

/*  position指定なし */
.modal {
    width: 100%;
    height: 100%;
}

position: fixed を指定することで、画面に固定されます。

/* position: fixed */
.modal {
    position: fixed;
    width: 100%;
    height: 100%;
}


応用:動的にモーダルのコンテンツを変更

モーダルの内容を動的に変更することもできます。

function openModal(title, content) {
    const modal = document.getElementById('myModal');
    const modalContent = document.querySelector('.modalContent');
    
    // コンテンツを変更
    modalContent.innerHTML = `
        <span class="close">&times;</span>
        <h2>${title}</h2>
        <p>${content}</p>
    `;
    
    // モーダルを表示
    modal.style.display = 'block';
    
    // 閉じるボタンのイベント設定(innerHTML後に必要)
    const closeBtn = document.getElementsByClassName('close')[0];
    closeBtn.addEventListener('click', () => {
        modal.style.display = 'none';
    });
}

// 使い方
openModal('お知らせ', '新機能がリリースされました!');
openModal('エラー', '入力内容に誤りがあります。');

innerHTML を使うと、内部の要素が再生成されるため、イベントリスナーを再設定する必要があります。

確認ダイアログの例

削除確認などに使えるモーダルです。

function confirmDelete(itemName, onConfirm) {
    const modal = document.getElementById('myModal');
    const modalContent = document.querySelector('.modalContent');
    
    modalContent.innerHTML = `
        <span class="close">&times;</span>
        <h2>削除確認</h2>
        <p>「${itemName}」を削除しますか?</p>
        <button id="confirmBtn" style="background-color: #ff4444;">削除する</button>
        <button id="cancelBtn" style="background-color: #ddd; color: #333;">キャンセル</button>
    `;
    
    modal.style.display = 'block';
    
    // 削除ボタン
    document.getElementById('confirmBtn').addEventListener('click', () => {
        onConfirm();
        modal.style.display = 'none';
    });
    
    // キャンセルボタン
    document.getElementById('cancelBtn').addEventListener('click', () => {
        modal.style.display = 'none';
    });
    
    // 閉じるボタン
    document.getElementsByClassName('close')[0].addEventListener('click', () => {
        modal.style.display = 'none';
    });
}

// 使い方
confirmDelete('タスクA', () => {
    console.log('タスクAを削除しました');
    // 実際の削除処理をここに書く
});


まとめ

今回、モーダルを実装して学んだポイントです。

モーダルの実装には、CSSの position: fixed で画面に固定し、display: none/block で表示・非表示を切り替えます。rgba() を使うことで半透明の背景を作り、z-index で表示順序を制御します。

JavaScriptでは、e.target でクリックされた要素を判定することが重要です。これにより、背景だけクリックしたときに閉じる仕組みが作れます。また、getElementsByClassName() は配列を返すため、[0] で最初の要素を取得する必要があります。

モーダルは汎用的な機能なので、フォーム入力、確認ダイアログ、画像の拡大表示、お知らせの表示、エラーメッセージなど、様々な場面で使えます。innerHTML で動的にコンテンツを変更することで、1つのモーダルを使い回すこともできます。

基本的な実装を理解すれば、自分のプロジェクトに合わせてカスタマイズできるようになります。


関連記事:


カテゴリー: 開発記録
タグ: JavaScript, モーダル, CSS, position fixed, イベント処理

コメント

タイトルとURLをコピーしました