サムネイル画像をクリックすると大きな画像をモーダル表示するライトボックス機能は、商品ギャラリーやポートフォリオでよく使われます。この記事ではjQueryの自作モーダル・Fancybox・キーボード操作・アクセシビリティ対応まで解説します。
この記事でわかること
- jQueryだけで画像モーダルを自作する方法
- Fancyboxライブラリを使った簡単実装
- Escキー・背景クリックで閉じる実装
- キーボードとアクセシビリティへの対応
- ライブラリを使わない dialog 要素による実装
実装方法の比較
| 方法 | メリット | デメリット |
|---|---|---|
| jQuery自作 | 依存ゼロ・完全カスタマイズ可能 | 実装コストが高い・スワイプ等は自前 |
| Fancybox | 多機能・ギャラリー対応・タッチ操作 | ライブラリ追加が必要 |
| dialog要素 | 標準HTML・アクセシビリティ優秀 | 古いブラウザ非対応(IE) |
jQuery自作モーダルの実装
<!-- サムネイル --> <div class="gallery"> <img class="thumb" src="/img/photo1-thumb.jpg" data-src="/img/photo1.jpg" alt="写真1"> <img class="thumb" src="/img/photo2-thumb.jpg" data-src="/img/photo2.jpg" alt="写真2"> <img class="thumb" src="/img/photo3-thumb.jpg" data-src="/img/photo3.jpg" alt="写真3"> </div> <!-- モーダル(最初は非表示)--> <div id="modal-overlay" role="dialog" aria-modal="true" aria-label="画像の拡大表示" tabindex="-1"> <button id="modal-close" aria-label="閉じる">×</button> <img id="modal-img" src="" alt=""> </div>
#modal-overlay {
display: none;
position: fixed;
inset: 0;
background: rgba(0,0,0,0.8);
z-index: 1000;
cursor: pointer;
place-items: center;
}
#modal-overlay.is-open { display: grid; }
#modal-img {
max-width: 90vw;
max-height: 90vh;
cursor: default;
border-radius: 4px;
}
#modal-close {
position: absolute;
top: 16px;
right: 16px;
background: rgba(255,255,255,0.2);
border: none;
color: #fff;
font-size: 24px;
width: 40px;
height: 40px;
border-radius: 50%;
cursor: pointer;
line-height: 1;
}
.thumb { cursor: pointer; opacity: 0.9; transition: opacity 0.2s; }
.thumb:hover { opacity: 1; }
$(function () {
var $overlay = $('#modal-overlay');
var $img = $('#modal-img');
function openModal(src, alt) {
$img.attr({ src: src, alt: alt });
$overlay.addClass('is-open');
$overlay.focus(); // フォーカスをモーダルに移動
$('body').css('overflow', 'hidden'); // スクロール禁止
}
function closeModal() {
$overlay.removeClass('is-open');
$('body').css('overflow', '');
}
// サムネイルクリックで開く
$(document).on('click', '.thumb', function () {
openModal($(this).data('src'), $(this).attr('alt'));
});
// 閉じるボタン・背景クリックで閉じる
$('#modal-close').on('click', closeModal);
$overlay.on('click', function (e) {
if (e.target === this) closeModal(); // 画像自体はクリックしても閉じない
});
// Escキーで閉じる
$(document).on('keydown', function (e) {
if (e.key === 'Escape') closeModal();
});
});
data-src で拡大用URLをサムネイルと分ける
data-src 属性に元画像(大サイズ)のURLを設定し、src にはサムネイルを使います。これにより大画像をページロード時に読み込まず、クリック時に初めて読み込みます。Fancyboxライブラリを使った実装
Fancyboxはタッチ操作・ギャラリーナビゲーション・動画対応など多機能なライトボックスライブラリです。
<!-- CDNを読み込む --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui@5/dist/fancybox/fancybox.css"> <script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui@5/dist/fancybox/fancybox.umd.js"></script> <!-- ギャラリー(data-fancybox で同グループに) --> <a data-fancybox="gallery" href="/img/photo1.jpg"> <img src="/img/photo1-thumb.jpg" alt="写真1"> </a> <a data-fancybox="gallery" href="/img/photo2.jpg"> <img src="/img/photo2-thumb.jpg" alt="写真2"> </a>
// 初期化(デフォルト設定はHTMLだけで動作・オプション変更時に使用)
Fancybox.bind('[data-fancybox]', {
Toolbar: {
display: { left: ['infobar'], middle: [], right: ['close'] }
}
});
dialog要素を使った実装(ライブラリ不要・アクセシビリティ優秀)
<img class="thumb" src="/img/thumb.jpg" data-src="/img/large.jpg" alt="写真"> <dialog id="image-dialog"> <button id="dialog-close" autofocus>閉じる</button> <img id="dialog-img" src="" alt=""> </dialog>
$(function () {
var dialog = document.getElementById('image-dialog');
$('.thumb').on('click', function () {
$('#dialog-img').attr({ src: $(this).data('src'), alt: $(this).attr('alt') });
dialog.showModal(); // ネイティブモーダルとして開く
});
$('#dialog-close').on('click', function () {
dialog.close();
});
// 背景クリックで閉じる
$(dialog).on('click', function (e) {
if (e.target === dialog) dialog.close();
});
});
dialog要素はキーボードとアクセシビリティが充実
HTML5の
HTML5の
<dialog> 要素はブラウザ標準のモーダル機能を提供します。Escキーで自動的に閉じる・フォーカストラップ・スクリーンリーダー対応など、アクセシビリティが最初から考慮されています(IE非対応)。まとめ
jQueryで画像クリック拡大表示を実装する際のポイントをまとめます。
- 自作: オーバーレイ + モーダル画像 + Esc/背景クリックで閉じる
- data-src: サムネイルと大画像を分けて遅延読み込み
- アクセシビリティ:
role="dialog"・aria-modal="true"・フォーカス管理 - 多機能が必要: Fancybox(ギャラリー・タッチ・動画対応)
- 新規:
<dialog>要素が最もアクセシブル
関連記事: modal-video.jsでYouTubeをモーダル表示する方法 / imgタグのalt属性を取得・設定する完全ガイド
よくある質問(FAQ)
Q前後の画像に切り替えるナビゲーションを追加したいです。
A表示中の画像インデックスを変数で管理し、前後ボタンクリックでインデックスを更新します。
var thumbs = $(".thumb").toArray(); で全サムネイルを配列化し、currentIndex で管理する実装が一般的です。ギャラリーナビゲーションが必要な場合はFancyboxを使うと工数を大幅に削減できます。Q画像の読み込み中にローディングアニメーションを表示したいです。
Aモーダルを開いた直後にローダーを表示し、
$("#modal-img").on("load", ...) で画像読み込み完了後にローダーを非表示にします。loadstart・load・error の各イベントで状態を管理してください。Qスマホでスワイプして次の画像に切り替えたいです。
Atouchstart/touchendイベントでスワイプ方向を判定します(
touchendX - touchstartX が正=右スワイプ)。ただしタッチ操作対応はかなりの実装コストがかかるため、Fancyboxなどのライブラリを使う方が効率的です。QWordPressで投稿内の画像に自動でライトボックスを適用したいです。
AWordPressはコンテンツ内の画像を
<figure><a href="大画像URL"><img></a></figure> 構造にします。$(".entry-content a").has("img").each(function () { ... }) で投稿内の画像リンクにライトボックスを適用できます。Jetpackプラグインを使うと設定だけでカルーセル付きライトボックスが有効になります。Qモーダルを開いたときにバックグラウンドがスクロールしてしまいます。
Aモーダルを開くときに
$("body").css("overflow", "hidden")、閉じるときに $("body").css("overflow", "") とすることでスクロールを抑制できます。iOSの場合は position: fixed も必要なことがあります。dialog.showModal() を使うとブラウザが自動的に制御してくれます。