---
title: "アクセシビリティ診断サービスの証明書とレポートがPDF対応しました！"
date: 2025-11-16
categories: column
author: 二俣
canonical: https://www.liberogic.jp/topics/20251117-acccessibility-pdf/
---

# アクセシビリティ診断サービスの証明書とレポートがPDF対応しました！

![](https://images.microcms-assets.io/assets/4b13731f29254025b91c8d846198ffc9/db6bed48b1ba496c9ce25358c43e0a07/20251117-accessibilityPDF.png)

リベロジックのアクセシビリティ診断サービスでは証明書・レポートをHTML形式で提供していましたが「証明書をPDF形式で提供してほしい」という声にお応えし、PDF形式の証明書とレポートを発行できるようになりました！

リベロジックのアクセシビリティ診断サービスでは証明書・レポートをHTML形式で提供していましたが「証明書をPDF形式で提供してほしい」という声にお応えし、**PDF形式の証明書とレポート**を発行できるようになりました！

[PDFのウェブアクセシビリティ検査証明書](https://www.liberogic.jp/accessibility_report/pdf/accessibility-certificate.pdf)

[PDFのアクセシビリティ適合レポート（VPAT / ACR） ](https://www.liberogic.jp/accessibility_report/pdf/vpat-acr.pdf)

この対応にあたり、ビルドプロセスでHTMLを出力するのと同時にPDFを自動出力するシステムを構築しました。

## 🛠️ PDF化の基盤：Puppeteerと環境構築

PDF生成ツールとして、Chromiumブラウザをヘッドレスで操作できる**Puppeteer**を採用しました。もともとHTMLはAstroで構築されているため、Puppeteerの導入は比較的スムーズでした。

### 1. ローカルサーバーによるレンダリング環境の確保

PuppeteerはChromiumの印刷機能を利用しますが、ローカルのHTMLファイル（`file://`）を直接読み込むと、**レイアウトが崩れてしまう**問題が発生します。

これを回避するため、以下の環境を構築しました。

- **一時的なWebサーバー:** ビルド後の`dist`ディレクトリをホストする一時的なローカルWebサーバー（`http-server`）をNode.jsの子プロセスとして起動。
- **安定した環境:** Puppeteerにサーバー経由（`http://localhost:8080`）でアクセスさせることで、ブラウザと同一の安定したレンダリング環境を確保しました。

環境構築とサーバー起動のコード（抜粋）

```
`// プロジェクト定数からドメインを取得し、未設定なら localhost:8080 を使用
const HOST_DOMAIN = SITE_URL || `http://localhost:${PORT}`; 
const BUILD_ROOT = path.join(__dirname, 'dist');
const PORT = 8080;

// --- サーバーの起動ロジック ---
let serverProcess = exec(`npx http-server ${BUILD_ROOT} -p ${PORT} -s --silent`);

// サーバーが起動するまで待機
await new Promise((resolve) => setTimeout(resolve, 2000));

// --- Puppeteerのページアクセス ---
// Puppeteerは localhost:8080 にアクセスし、レンダリングを開始します
const serverUrl = `http://localhost:${PORT}/${REPORT_DIR}/${urlPath}`;
await page.goto(serverUrl, { waitUntil: 'networkidle0' });
`
```

### 2. 日本語フォントの適用

PDF生成を行うローカルサーバー環境には日本語フォントがないため、PDFに埋め込まれるフォントがおかしくなる問題が発生します。

- **フォントの回避策:** スクリプト内で、PDF生成直前にWebフォントの参照と適用スタイルをDOMに動的に挿入。これにより、日本語フォントでのPDF出力が可能に。 HTML側は速度を優先しWebフォントを使用していないため、このような動的挿入でPDFのみ適用されるようにしています。

フォント動的挿入のコード（抜粋）

```
`// Webフォントの動的挿入ロジック (page.evaluateでブラウザ側で実行)
await page.evaluate((fontUrl) => {
    // <link>タグを生成してDOMに挿入
    const link = document.createElement('link');
    link.rel = 'stylesheet';
    link.href = fontUrl;
    document.head.appendChild(link);
    
    // @media print スタイルを強制的に挿入し、フォントを適用
    const printStyle = document.createElement('style');
    printStyle.textContent = `
      @media print {
        html, body {
          font-family: 'Noto Sans JP', sans-serif !important;
        }
      }
    `;
    document.head.appendChild(printStyle);
}, WEBFONTS_URL);
`
```

## 🚨 最大の課題：PDF内リンクのURL参照問題

最も手こずったのは、**PDF間のリンク**でした。PDF内に埋め込まれたリンクが、デプロイ後もローカル開発環境のURL（`http://localhost:8080`）を参照してしまう問題です。 これは、ChromiumがHTMLをロードした際のベースURIをPDFリンクの基点として保持してしまうために起こります。

### リンクの強制絶対パス化

これを解消するため、以下の手順でリンクをデプロイ後の完全な絶対パスに強制的に書き換えました。

1. **デプロイ先ドメインの利用:** プロジェクトの定数（`SITE_URL`）からデプロイ先のドメイン（例：`https://example.com`）を取得。
2. **絶対URLの構築と置換:** Node.jsでHTMLの内容を取得し、元のリンク（`/accessibility_report/top/`）を、**取得したドメイン**を基点とした完全なURL（例：`https://example.com/accessibility_report/pdf/acr-top.pdf`）に書き換えます。
3. **DOMへの再適用:** 書き換え後のHTMLをChromiumに再適用（`page.setContent()`）することで、PDFに埋め込まれるリンクを**意図したデプロイ後のドメイン**に確実に固定しました。

リンク書き換えのコード（抜粋）

```
`// 1. 無効化したいリンク（.link-ignore-pdf）を物理的に削除
const ignoreLinkRegex = new RegExp(`(<a\\\\s+[^>]*class=["'][^"']*${ignoreClass}[^"']*["'][^>]*>)(.*?)(<\\/a\\\\s*>)`, 'gi');
content = content.replace(ignoreLinkRegex, '$2'); // <a>タグ全体を中身のテキストに置換

// 2. 詳細ページへのリンクを絶対URLに書き換え
const detailLinkRegex = new RegExp(`href="${reportDirRootLink}([^/]+)\\/"`, 'g');
const detailPdfUrl = `${pdfAbsoluteUrl}/acr-top.pdf`; // 例

content = content.replace(detailLinkRegex, (match, slug) => {
    // リンクを <http://localhost>... ではなく、<https://example.com/>... に強制置換
    return `href="${pdfAbsoluteUrl}/acr-${slug}.pdf"`; 
});

// 3. 最終的なコンテンツをブラウザに再適用し、PDF出力へ
await page.setContent(content, { 
    waitUntil: 'domcontentloaded',
    baseURL: baseUrlForContent
});
`
```

## 🎉 まとめ

今回はPDF間でリンクするという少し特殊な要件があったため手こずりましたが、Puppeteerの導入自体は割とすんなりでした。ビルドも早いですし、非常に便利なツールだと感じました！

今回の対応のポイントは以下です:

- ローカルサーバー経由でのレンダリングによる安定性確保
- 動的なWebフォント注入による日本語対応
- リンクの絶対パス化によるPDF間のリンク

PDF対応により、サービスの利便性は大きく向上しました。これからも、お客様にとって価値あるアクセシビリティ診断サービスの品質を追求していきます！
