Next.js + react-pdfを利用 iPhoneでPDF1ページしか表示されない解決方法

react-pdf 実装

iPhone Safari での PDF 全ページ表示問題を解決するため、<iframe> を使った PDF 表示を廃止し、react-pdf を用いた全ページレンダリングに切り替えた。 iframe では、 iOS Safari において PDF が1ページ目しか表示されなかった。

使用パッケージとバージョン

パッケージバージョン備考
react-pdf^10.4.1Document / Page コンポーネント提供
pdfjs-dist^5.4.296react-pdf が内部で使うバージョンに合わせる(重要)

インストール

pnpm install react-pdf pdfjs-dist@5.4.296

pdfjs-dist のバージョンは必ず react-pdf が要求するものに揃えること。 バージョンが異なると後述のバージョン不一致エラーが発生する。

遭遇したエラーと解決

エラー 1: DOMMatrix is not defined(SSRエラー)

エラー内容:
const SCALE_MATRIX = new DOMMatrix();
digest: ‘534975899’

原因: pdfjs-dist のモジュール初期化時に DOMMatrix(ブラウザ専用API)を使用しているため、 Next.js の SSR フェーズ(Node.js 環境)でクラッシュする。
'use client' を付けてもモジュールの初期化はサーバーで走るため回避できない。

解決策: react-pdf を使うコンポーネントを別ファイル(PdfViewer.tsx)に分離し、next/dynamic の ssr: false でクライアントのみ読み込む。

// IntroMediaOverlay.tsx
import dynamic from 'next/dynamic';

const PdfViewer = dynamic(
  () => import('@/components/PdfViewer'),
  { ssr: false }
);

エラー 2: API version does not match Worker version

エラー内容:
UnknownErrorException: The API version "5.4.296" does not match the Worker version "5.5.207".

原因: package.json に直接インストールされた pdfjs-dist が 5.5.207 だったのに対し、react-pdf 内部が使う pdfjs-dist は 5.4.296 だった。 Worker ファイルの解決に 5.5.207、API には 5.4.296 が使われバージョン不一致になった。

解決策: pdfjs-dist を react-pdf が要求するバージョンに固定する。

pnpm install pdfjs-dist@5.4.296

確認方法:

cat node_modules/react-pdf/package.json | grep pdfjs-dist
# → "pdfjs-dist": "5.4.296"

実装コード

PdfViewer.tsx(react-pdf 本体)

// src/components/PdfViewer.tsx
'use client';

import { useRef, useState, useCallback } from 'react';
import { Document, Page, pdfjs } from 'react-pdf';
import 'react-pdf/dist/Page/AnnotationLayer.css';
import 'react-pdf/dist/Page/TextLayer.css';

pdfjs.GlobalWorkerOptions.workerSrc = new URL(
  'pdfjs-dist/build/pdf.worker.min.mjs',
  import.meta.url,
).toString();

export default function PdfViewer({ url }: { url: string }) {
  const [numPages, setNumPages] = useState<number>(0);
  const containerRef = useRef<HTMLDivElement>(null);
  const [containerWidth, setContainerWidth] = useState<number>(600);

  const onDocumentLoadSuccess = useCallback(
    ({ numPages }: { numPages: number }) => {
      setNumPages(numPages);
      if (containerRef.current) {
        setContainerWidth(containerRef.current.clientWidth);
      }
    },
    []
  );

  return (
    <div ref={containerRef} className="overflow-y-auto max-h-[60vh] p-2">
      <Document
        file={url}
        onLoadSuccess={onDocumentLoadSuccess}
        loading={<span>PDF読み込み中...</span>}
      >
        {Array.from({ length: numPages }, (_, i) => (
          <Page
            key={i}
            pageNumber={i + 1}
            width={containerWidth - 16}
            className="mb-2"
          />
        ))}
      </Document>
    </div>
  );
}
Win版 Jsree スクショ 無音ガメラ Web版

HTML・CSS・JavaScriptでスマホ&PC対応のダークモードを自動手動切替 実装

スマホ&PC対応のダークモード

HTML・CSS・JavaScriptのみを使って、スマホとPCの両方に対応したダークモードの自動&手動切り替え機能を実装する方法を詳しく解説します。


ダークモードに対応するメリット

  • 夜間の閲覧がしやすく、目の負担を軽減?
  • デバイスのバッテリー消費を抑制?(OLEDディスプレイの場合)
  • ユーザーのOS設定に合わせたUIで満足度向上

方法1:CSSだけで実現する自動ダークモード

ユーザーのOSやブラウザの設定に応じて自動的に切り替えるには、以下のように prefers-color-scheme メディアクエリを使います。

/* 通常(ライトモード) */
body {
  background-color: white;
  color: black;
}

/* ダークモード */
@media (prefers-color-scheme: dark) {
  body {
    background-color: #121212;
    color: white;
}

方法2:JavaScriptとlocalStorageを使った手動切り替え

ユーザーがボタンを使って自分でライト/ダークを切り替えたい場合は、以下の3つのファイルを用意します。

1. 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>
  <button id="toggle-theme">テーマ切り替え</button>
  <h1>こんにちは、世界!</h1>
  <p>ライト/ダークテーマを自動&手動で切り替えできます。</p>
  <script src="script.js"></script>
</body>
</html>

2. CSSコード

:root {
  --bg-color: white;
  --text-color: black;
}

[data-theme="dark"] {
  --bg-color: #121212;
  --text-color: white;
}

body {
  background-color: var(--bg-color);
  color: var(--text-color);
  font-family: sans-serif;
  transition: background-color 0.3s, color 0.3s;
}

button {
  margin: 1rem;
  padding: 0.5rem 1rem;
  cursor: pointer;
}

3. JavaScriptコード

const toggleButton = document.getElementById('toggle-theme');
const userPrefKey = 'theme';

function applyTheme(theme) {
  document.documentElement.setAttribute('data-theme', theme);
}

function initTheme() {
  const savedTheme = localStorage.getItem(userPrefKey);
  if (savedTheme) {
    applyTheme(savedTheme);
  } else {
    const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
    applyTheme(systemPrefersDark ? 'dark' : 'light');
  }
}

toggleButton.addEventListener('click', () => {
  const current = document.documentElement.getAttribute('data-theme');
  const newTheme = current === 'dark' ? 'light' : 'dark';
  applyTheme(newTheme);
  localStorage.setItem(userPrefKey, newTheme);
});

initTheme();

スマホ&PC対応状況(2025年最新)

デバイス/ブラウザ対応状況
iOS Safari✅ 完全対応
Android Chrome✅ 完全対応
Windows Edge / Chrome✅ 完全対応
macOS Safari / Chrome✅ 完全対応

ユーザーフレンドリー&SEOにも有利なダークモード対応

今回紹介したように、HTML・CSS・JavaScriptだけで、OS設定連動+手動切替が可能なダークモード対応を簡単に実装できます。
ダークモードは単なる見た目だけでなく、ユーザー体験やサイト評価向上に貢献します。ぜひあなたのWebサイトにも導入してみてください。


MBTI診断 | あなたの性格タイプを分析

PNGをファビコン(favicon.ico)に変換

Googleサーチコンソールに反映されるための最低限のSEO構造とは

Googleサイト確認のTXTレコードをnslookupで確認する方法

PHPで複数ファイルを順番に削除する方法

iPhone のパスワード設定で アルファベットを含めた場合 パスワード解除キーボードが出ない場合がある

iPhoneパスワード画面

パスワードをアルファベット+数字

iPhone のパスワードを解除する場合に出てくる下の画面

iPhoneパスワード解除画面

設定を アルファベット+数字にできるようなんです。(私のiPhone英語モードなのですいません)

iPhoneパスワード設定画面

上記の設定で パスワードを「アルファベット + 数字」に設定した場合、

パスワード解除画面で 通常はアルファベット入力のキーボードが出るらしいです。

パスワード解除キーボードが出ない場合

しかし、 iPhoneのバグか何かの影響でこのキーボードが出なくなる場合もあり

再起動しても アルファベット用のキーボードが出ない場合は、

パソコンや他のスマホのブラウザから iCloudにアクセスし、iPhoneを初期化するしか方法ないようです

MBTI診断 | あなたの性格タイプを分析 【無料・登録不要】

簡単PDFファイル結合|パスワード設定方法