【jQuery】画像クリックで拡大表示する完全ガイド|自作モーダル・Fancybox・キーボード対応・アクセシビリティまで

サムネイル画像をクリックすると大きな画像をモーダル表示するライトボックス機能は、商品ギャラリーやポートフォリオでよく使われます。この記事では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="閉じる">&times;</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の <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", ...) で画像読み込み完了後にローダーを非表示にします。loadstartloaderror の各イベントで状態を管理してください。
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() を使うとブラウザが自動的に制御してくれます。