【jQuery】PDFをモーダルウィンドウで表示する完全ガイド|Bootstrap 4/5・iframe・PDF.js・モバイル対応まで

PDFをダウンロードさせずにブラウザ上でプレビューさせたいとき、モーダルウィンドウ内に表示するUIは効果的です。しかし iframeがモバイルで動作しない問題Bootstrap 4と5のAPI差異など、つまずきポイントも多い実装です。本記事ではiframeの基本から、PDF.jsを使った高機能ビューア、モバイル対応まで体系的に解説します。

この記事でわかること

  • iframeでPDFをBootstrap 5モーダルに表示する基本実装
  • Bootstrap 4との違い(data-dismiss / data-bs-dismiss)
  • 複数のPDFリンクから共通モーダルを使う実装
  • モーダルを閉じたときにiframeをリセットする方法
  • iframeが効かないモバイルへの対応策(Google Drive・PDF.js)
  • PDF.jsで独自ビューアをモーダルに組み込む方法
  • ダウンロードボタン付きのPDFプレビューUI
スポンサーリンク

iframeでPDFをモーダルに表示する基本実装(Bootstrap 5)

Bootstrap 5を使ったシンプルな実装です。ボタンをクリックするとモーダルが開き、iframeにPDFが表示されます。

必要なライブラリの読み込み

<!-- Bootstrap 5 CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">

<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>

<!-- Bootstrap 5 JS(Popperバンドル版) -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>

モーダルのHTML構造

<!-- 表示ボタン -->
<button type="button"
        class="btn btn-primary"
        data-bs-toggle="modal"
        data-bs-target="#pdfModal"
        data-pdf-url="/files/sample.pdf">
  PDFをプレビュー
</button>

<!-- モーダル -->
<div class="modal fade" id="pdfModal" tabindex="-1" aria-labelledby="pdfModalLabel" aria-hidden="true">
  <div class="modal-dialog modal-xl modal-dialog-centered">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="pdfModalLabel">PDFプレビュー</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="閉じる"></button>
      </div>
      <div class="modal-body p-0">
        <iframe id="pdf-iframe" src="" width="100%" height="600" style="border:none;"></iframe>
      </div>
    </div>
  </div>
</div>

jQueryでiframeのsrcを制御する

$(function () {
  var $modal = $('#pdfModal');
  var $iframe = $('#pdf-iframe');

  // ボタンクリックでURLをiframeにセット
  $('[data-bs-toggle="modal"][data-pdf-url]').on('click', function () {
    var url = $(this).data('pdf-url');
    $iframe.attr('src', url);
  });

  // モーダルを閉じたらiframeをリセット(読み込みを止める)
  $modal[0].addEventListener('hidden.bs.modal', function () {
    $iframe.attr('src', '');
  });
});
モーダルを閉じるときにsrcを空にする理由
iframeのsrcをリセットしないと、モーダルを閉じた後もバックグラウンドでPDFの読み込みや描画が続き、パフォーマンスに影響します。hidden.bs.modal イベントはモーダルが完全に非表示になった後に発火するため、アニメーション中に src が空になって表示が崩れることもありません。

Bootstrap 4との違いと対応方法

Bootstrap 4から5に移行したプロジェクト、または古いテンプレートを使っている場合はAPIの差異に注意してください。

項目 Bootstrap 4 Bootstrap 5
モーダル表示ボタン属性 data-toggle=”modal” data-bs-toggle=”modal”
閉じるボタン属性 data-dismiss=”modal” data-bs-dismiss=”modal”
jQuery依存 必須 不要(独立して動作)
非表示イベント名 hidden.bs.modal hidden.bs.modal(同じ)
JSでモーダル操作 $(“#id”).modal(“show”) new bootstrap.Modal(el).show()

Bootstrap 4版のjQueryコード

// Bootstrap 4版
$(function () {
  $('#showPdfBtn').on('click', function () {
    var url = $(this).data('pdf-url');
    $('#pdf-iframe').attr('src', url);
    $('#pdfModal').modal('show');  // Bootstrap 4のjQuery API
  });

  $('#pdfModal').on('hidden.bs.modal', function () {
    $('#pdf-iframe').attr('src', '');
  });
});
Bootstrap 5でjQuery APIは使えない
Bootstrap 5では $("#id").modal("show") のjQuery連携APIが廃止されました。jQueryで制御する必要がある場合は new bootstrap.Modal(document.getElementById("id")).show() を使ってください。

複数のPDFリンクから共通モーダルを使う

ページ内に複数のPDFリンクがある場合、モーダルを1つ共有してそれぞれのPDFを表示するパターンです。

<!-- 複数のPDFリンク -->
<a href="#" class="pdf-link" data-pdf-url="/files/report-2024.pdf" data-pdf-title="2024年度 年次報告書">2024年度 年次報告書</a>
<a href="#" class="pdf-link" data-pdf-url="/files/catalog.pdf" data-pdf-title="製品カタログ">製品カタログ</a>
<a href="#" class="pdf-link" data-pdf-url="/files/manual.pdf" data-pdf-title="取扱説明書">取扱説明書</a>

<!-- 共通モーダル -->
<div class="modal fade" id="pdfModal" tabindex="-1" aria-hidden="true">
  <div class="modal-dialog modal-xl modal-dialog-centered">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="pdf-modal-title"></h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="閉じる"></button>
      </div>
      <div class="modal-body p-0">
        <iframe id="pdf-iframe" src="" width="100%" height="600" style="border:none;"></iframe>
      </div>
    </div>
  </div>
</div>
$(function () {
  var modal = new bootstrap.Modal(document.getElementById('pdfModal'));

  $('.pdf-link').on('click', function (e) {
    e.preventDefault();
    var url   = $(this).data('pdf-url');
    var title = $(this).data('pdf-title');

    $('#pdf-iframe').attr('src', url);
    $('#pdf-modal-title').text(title);
    modal.show();
  });

  document.getElementById('pdfModal').addEventListener('hidden.bs.modal', function () {
    $('#pdf-iframe').attr('src', '');
  });
});

モバイル対応:iframeが効かない場合の対処法

iOS Safariの多くのバージョンでは <iframe> 内のPDFが表示されず、ダウンロードが促されます。モバイルユーザーに対応するには代替手段が必要です。

Google Driveビューアを使う方法

// PDFのURLをGoogle Driveビューア経由に変換
function toGoogleViewerUrl(pdfUrl) {
  var encoded = encodeURIComponent(pdfUrl);
  return 'https://docs.google.com/viewer?embedded=true&url=' + encoded;
}

$(function () {
  $('.pdf-link').on('click', function (e) {
    e.preventDefault();
    var rawUrl   = $(this).data('pdf-url');
    var viewUrl  = toGoogleViewerUrl(rawUrl);
    $('#pdf-iframe').attr('src', viewUrl);
    new bootstrap.Modal(document.getElementById('pdfModal')).show();
  });
});
Google Driveビューアの注意点

  • PDFのURLは公開アクセス可能なURLである必要があります(localhost不可)
  • Google Driveビューアの利用はGoogleの利用規約に従います
  • 大きなPDFはGoogle側でのレンダリングに時間がかかることがあります

デバイス判定で挙動を切り替える方法

$(function () {
  $('.pdf-link').on('click', function (e) {
    e.preventDefault();
    var url = $(this).data('pdf-url');

    // iOSかどうかを判定
    var isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);

    if (isIOS) {
      // iOS: 新しいタブで直接開く(ダウンロードを促す代わりにプレビュー可能)
      window.open(url, '_blank');
    } else {
      // それ以外: モーダルで表示
      $('#pdf-iframe').attr('src', url);
      new bootstrap.Modal(document.getElementById('pdfModal')).show();
    }
  });
});

PDF.jsを使った高機能ビューア

Mozilla製のオープンソースPDFビューア PDF.js を使うと、iframeの代わりに独自のPDFレンダリングエンジンを使えるためクロスブラウザ・モバイル対応が向上します。

PDF.jsビューアURLを使う方法(最も簡単)

<!-- PDF.jsのビューアURLを iframe の src に指定する -->
<!-- CDN: https://mozilla.github.io/pdf.js/web/viewer.html?file=YOUR_PDF_URL -->
<iframe
  id="pdfjs-iframe"
  src=""
  width="100%"
  height="600"
  style="border:none;">
</iframe>
$(function () {
  var PDFJS_VIEWER = 'https://mozilla.github.io/pdf.js/web/viewer.html?file=';

  $('.pdf-link').on('click', function (e) {
    e.preventDefault();
    // 絶対URLに変換(PDF.jsビューアはフルURLが必要)
    var pdfUrl  = location.origin + $(this).data('pdf-url');
    var viewUrl = PDFJS_VIEWER + encodeURIComponent(pdfUrl);
    $('#pdfjs-iframe').attr('src', viewUrl);
    new bootstrap.Modal(document.getElementById('pdfModal')).show();
  });
});
PDF.jsビューアの利点

  • ページサムネイル・テキスト検索・印刷・フルスクリーンなどが標準装備
  • モバイルでもページスクロールが滑らか(iframeより優れる)
  • CDN版はサードパーティ制限でCORSエラーになることがあるため、本番環境ではPDF.jsをダウンロードして自サーバーに配置することを推奨

ダウンロードボタン付きPDFプレビューUI

モーダルフッターにダウンロードボタンを設置して、「プレビューを確認してからダウンロード」というUXを提供します。

<div class="modal fade" id="pdfModal" tabindex="-1" aria-hidden="true">
  <div class="modal-dialog modal-xl modal-dialog-centered">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="pdf-modal-title"></h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="閉じる"></button>
      </div>
      <div class="modal-body p-0">
        <iframe id="pdf-iframe" src="" width="100%" height="560" style="border:none;"></iframe>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">閉じる</button>
        <a id="pdf-download-btn" href="#" download class="btn btn-primary">ダウンロード</a>
      </div>
    </div>
  </div>
</div>
$(function () {
  $('.pdf-link').on('click', function (e) {
    e.preventDefault();
    var url   = $(this).data('pdf-url');
    var title = $(this).data('pdf-title') || 'PDFプレビュー';

    $('#pdf-iframe').attr('src', url);
    $('#pdf-modal-title').text(title);
    $('#pdf-download-btn').attr('href', url);  // ダウンロードボタンにも同じURLをセット

    new bootstrap.Modal(document.getElementById('pdfModal')).show();
  });

  document.getElementById('pdfModal').addEventListener('hidden.bs.modal', function () {
    $('#pdf-iframe').attr('src', '');
  });
});

実装方法の比較と選び方

方法 モバイル対応 外部依存 機能 向いている用途
iframe(直接) △(iOS非対応) なし 最小限 PC向け・社内ツール
Google Driveビューア Google依存 基本的 公開PDFのプレビュー
PDF.jsビューア PDF.jsのみ 高機能 汎用・モバイル重視

まとめ

PDF をモーダルで表示する際は、まず対象ユーザーがモバイルを使うかどうかを確認してください。PC専用の社内ツールならiframe直接が最もシンプルです。モバイル対応が必要な場合はPDF.jsを検討してください。

関連記事: 画像をクリックすると拡大表示する方法 / modal-video.jsでYouTube動画をモーダル表示する方法 / ボタンクリックで要素の表示・非表示を切り替える方法

よくある質問(FAQ)

QiPhoneでPDFがモーダルに表示されず、ダウンロードされてしまいます。
AiOS Safariはiframe内のPDF表示をサポートしていません。セクション「モバイル対応」で紹介したデバイス判定でiOSには新しいタブで開く方法か、Google DriveビューアURLまたはPDF.jsを使ってください。
Qモーダルを閉じてもPDFの読み込みが続いています。
Ahidden.bs.modal イベントで $('#pdf-iframe').attr('src', '') を呼んでいるか確認してください。srcを空文字に設定することでブラウザがiframeの読み込みを中止します。
QPDFをモーダルで表示する際に「許可されていません」エラーが出ます。
APDFが別のドメインにある場合、サーバーがCORSヘッダーを返していない可能性があります。また、PDFが X-Frame-Options: DENY または SAMEORIGIN を返している場合はiframeでの表示が拒否されます。自分のサーバーのPDFであれば、Content-Security-PolicyとX-Frame-Optionsの設定を確認してください。
Qモーダルの高さを画面サイズに合わせて自動調整したいです。
AiframeのheightをCSSで height: calc(100vh - 200px) に設定すると、ビューポートの高さからヘッダー・フッターの分を引いた高さに自動調整されます。モーダル自体に modal-dialog-scrollable クラスを付けるとモーダル内でスクロールも可能です。
QBootstrapを使わずにモーダルでPDFを表示できますか?
Aはい。CSS+jQueryだけでモーダルを自作して同様のことができます。position:fixed; top:0; left:0; width:100%; height:100%; の背景レイヤーとiframeを含むコンテンツボックスを配置し、jQueryでshow/hideを制御します。Bootstrapの依存を避けたい軽量なページに有効です。