こんにちは、かつコーチです。
「レガシー案件を保守することになったけど、jQueryでモーダルを実装した箇所がどう動いているか読めない」という相談をよく受けます。
モーダルウィンドウは、画像の拡大表示や確認ダイアログなど、どんなサイトでも一度は登場する定番のUIパーツです。
この記事では、jQueryを使ったモーダルの実装方法を、素のJavaScript版と対比しながら解説します。
すでに素のJavaScript版のモーダル実装を読んだ方は、「同じ動きをjQueryで書くとどう変わるか」に注目して読んでみてください。
モーダルウィンドウの基本構造
HTMLとCSSは素のJS版と同じ
jQueryを使う場合でも、HTMLとCSSの構造は素のJavaScript版とまったく変わりません。
<button class="open-modal-btn" id="openModalBtn">お問い合わせ</button>
<div class="modal-overlay" id="modalOverlay">
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="modalTitle">
<button class="modal__close" id="modalCloseBtn" aria-label="閉じる">×</button>
<h2 id="modalTitle">お問い合わせ</h2>
<p>ご相談内容をお気軽にお送りください。</p>
<form>
<textarea rows="4" placeholder="お問い合わせ内容"></textarea>
<button type="submit">送信する</button>
</form>
</div>
</div>
.modal-overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.5);
display: none;
align-items: center;
justify-content: center;
z-index: 100;
}
.modal-overlay.is-open {
display: flex;
}
.modal {
background: #fff;
border-radius: 8px;
padding: 24px;
width: 90%;
max-width: 400px;
position: relative;
}
モーダルウィンドウとは、元のページの上に別レイヤーとして表示される小窓のことです。
jQueryが変えるのは、あくまで「JavaScript側の書き方」だけだと覚えておいてください。
手順1:セレクタと開閉のメソッドを書く
素のJavaScriptでは document.getElementById() で要素を取得していましたが、jQueryでは $() にセレクタを渡すだけで済みます。
$(function () {
const $openBtn = $('#openModalBtn');
const $closeBtn = $('#modalCloseBtn');
const $overlay = $('#modalOverlay');
function openModal() {
$overlay.addClass('is-open');
}
function closeModal() {
$overlay.removeClass('is-open');
}
$openBtn.on('click', openModal);
$closeBtn.on('click', closeModal);
});
$(function () { ... }) は、DOMの読み込み完了後に処理を実行するjQuery特有の書き方です。
素のJavaScriptで DOMContentLoaded イベントを使っていた処理が、この1行に置き換わっています。
classList.add() / classList.remove() が、それぞれ addClass() / removeClass() に対応している点にも注目してください。
jQueryオブジェクトを変数に入れるとき、慣習として変数名の先頭に $ を付けておくと、「これはjQueryオブジェクトだ」と一目で分かりやすくなります。
手順2:背景クリックで閉じる処理
素のJavaScript版では event.target === modalOverlay という判定で「背景自体がクリックされたか」を見分けていました。
jQueryでも考え方はまったく同じです。
$overlay.on('click', function (event) {
if (event.target === this) {
closeModal();
}
});
jQueryのイベントハンドラ内では、this がイベントを登録した要素(この場合は modalOverlay)を指します。
event.target はDOM標準のプロパティなので、jQueryでもそのまま使えるのがポイントです。
よくあるつまずきポイント・エラー対処
Before/After:背景のスクロールが止まらない
私が初めてjQueryでモーダルを実装したとき、開閉ボタンだけ作って満足してしまい、スマホで確認したら背景がスクロールできてしまう不具合に気づきました。
素のJS版でも同じつまずきが紹介されていましたが、jQueryでも構造は同じなので、まったく同じ落とし穴にハマります。
❌ Before:bodyの状態を何も変えていない
function openModal() {
$overlay.addClass('is-open');
}
// bodyにクラスを付けていないため、スマホで指をなぞると背景がスクロールしてしまう
✅ After:bodyにスクロール禁止用のクラスを付ける
body.is-modal-open {
overflow: hidden;
}
function openModal() {
$overlay.addClass('is-open');
$('body').addClass('is-modal-open'); // 背景のスクロールを禁止
}
function closeModal() {
$overlay.removeClass('is-open');
$('body').removeClass('is-modal-open'); // 元に戻す
}
開くときに付けたクラスは、閉じるときに必ず外す、というペアで確認する習慣をつけると、この手のバグを防げます。
Before/After:$は定義されていませんエラー
もう1つ、jQuery特有のエラーとしてよくハマるのが $ is not defined です。
私が実際に社内の古いテンプレートを触っていたとき、モーダルのスクリプトをコピーして貼り付けたら、コンソールにこのエラーが出ました。
❌ Before:jQuery本体の読み込み忘れ
<script src="script.js"></script>
</body>
自作のスクリプトファイルだけを読み込んでいて、jQuery本体(jquery.min.js)を読み込んでいないと、$という関数自体が存在しないため、コンソールに Uncaught ReferenceError: $ is not defined と表示されます。
✅ After:jQuery本体を先に読み込む
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="script.js"></script>
</body>
<script> タグの読み込み順序も重要です。
jQuery本体を先に読み込み、それに依存する自作スクリプト(script.js)を後に読み込む、という順番を必ず守ってください。
応用:ESCキー対応とアニメーション
fadeIn/fadeOutで滑らかに表示する
jQueryならではの応用として、addClass/removeClassの代わりに fadeIn() / fadeOut() を使うと、CSSアニメーションを書かなくても簡単にフェード演出が付けられます。
function openModal() {
$overlay.fadeIn(200); // 200ミリ秒かけてフェードイン
$('body').addClass('is-modal-open');
}
function closeModal() {
$overlay.fadeOut(200); // 200ミリ秒かけてフェードアウト
$('body').removeClass('is-modal-open');
}
ただし fadeIn() / fadeOut() を使う場合、CSS側の display: none の指定は不要になります。
fadeIn() は内部で display を自動的に切り替えてくれるため、CSSで .is-open クラスによる表示制御をしていると、逆に競合して意図通りに動かなくなることがあります。
addClassによるクラス制御とfadeIn/fadeOutによるアニメーション制御は、どちらか一方に統一するのがおすすめです。
ESCキーで閉じる
キーボード操作への配慮も、素のJS版と同じ考え方で実装できます。
$(document).on('keydown', function (event) {
if (event.key === 'Escape' && $overlay.hasClass('is-open')) {
closeModal();
}
});
classList.contains() に対応するのが hasClass() です。
$(document) のように、document オブジェクトそのものをjQueryオブジェクト化してイベントを登録できる点も覚えておくと便利です。
まとめ
この記事のポイント
- HTMLとCSSの構造は素のJavaScript版と変わらず、変わるのはJavaScript側の書き方だけ
classList.add/removeはaddClass()/removeClass()、event.target === thisの判定は素のJSと同じ考え方で書ける- 背景のスクロール禁止は、開閉のペアでクラスを付け外しする習慣を忘れずに
- jQuery本体の読み込み忘れは
$ is not definedエラーの定番原因なので、<script>タグの順序を確認する fadeIn()/fadeOut()を使うとアニメーションを簡単に付けられるが、クラスによる表示制御とは混在させない
次に読むべき記事
次回は、スライドショー・カルーセルをjQueryで実装します。
animate()メソッドとsetIntervalを組み合わせた、少し複雑な状態管理が登場します。
→ 次の記事:スライドショー・カルーセルをjQueryで実装する
タグ:jQuery, 初心者向け, UI実装