wkhtmltopdf から移行する完全ガイド|@page・CSS・日本語フォント対応
wkhtmltopdfを使っているプロジェクトで「@page { size: A4; margin: 0; } が効かない」「日本語が文字化けする」「CSS Gridが崩れる」といった問題に悩んでいる開発者は多いです。
原因はシンプルです。wkhtmltopdf は2012年に開発が始まったWebKitベースのツールで、現代のCSSを完全にはサポートしていません。そして現在、wkhtmltopdfの開発は事実上停止しています。
この記事では、wkhtmltopdfの主な限界とChromiumベースエンジンの違いを解説し、FUNBREW PDFへのスムーズな移行手順をコード付きで紹介します。
wkhtmltopdf の現状と EOL 問題
開発停止の経緯
wkhtmltopdf の最終安定版は 0.12.6(2020年リリース) です。GitHubのissueでもメンテナーが「アクティブメンテナンスは終了」と明言しており、以下の問題が未解決のまま残っています:
- セキュリティパッチの未提供
- Qt 5 への完全対応なし
- モダンなCSSプロパティへの非対応
- PDF/Aへの非対応
wkhtmltopdf を使い続けるリスク
| リスク | 影響 |
|---|---|
| セキュリティパッチなし | SSRF攻撃やXSS経由の情報漏洩リスク |
| CSS非対応の拡大 | UI改修のたびにPDFが崩れる |
| OS依存のフォント問題 | サーバー移行時に日本語が文字化け |
| 採用難航 | 新メンバーが使いやすいドキュメントが少ない |
wkhtmltopdf と Chromium の CSS 互換性比較
移行前に知っておくべき主要な差異をまとめます。
@page ルールの動作差異
最もよく問題になる @page の動作比較:
/* Chromiumでは完全動作 / wkhtmltopdfでは一部無視される */
@page {
size: A4;
margin: 0; /* wkhtmltopdf: コマンドラインオプションが優先 */
margin-top: 20mm;
margin-bottom: 20mm;
}
/* Chromiumのみ対応 */
@page :first {
margin-top: 60mm; /* 表紙ページの余白設定 */
}
/* Chromiumのみ対応 */
@page {
@bottom-center {
content: counter(page) " / " counter(pages); /* ページ番号 */
}
}
wkhtmltopdf で @page { size: A4; margin: 0; } を使ってもデフォルト余白が残る場合、コマンドラインオプションで上書きが必要でした:
# wkhtmltopdf 時代の余白制御(コマンドラインオプション必須)
wkhtmltopdf \
--margin-top 0 \
--margin-right 0 \
--margin-bottom 0 \
--margin-left 0 \
--page-size A4 \
input.html output.pdf
Chromiumベースエンジンでは CSSの @page が仕様通りに動作します:
/* これだけで余白ゼロA4が実現する */
@page {
size: A4;
margin: 0;
}
CSS 機能の対応比較
| CSS機能 | wkhtmltopdf | Chromium(FUNBREW PDF) |
|---|---|---|
@page margin |
部分対応(CLIオプション優先) | 完全対応 |
@page margin-box(ヘッダー/フッター) |
非対応 | 対応 |
break-inside: avoid |
部分対応 | 完全対応 |
| CSS Grid | 非対応 | 対応 |
| CSS Flexbox(モダン) | 部分対応 | 完全対応 |
| CSS カスタムプロパティ(変数) | 非対応 | 対応 |
position: sticky |
非対応 | 対応 |
| SVGレンダリング | 不安定 | 安定 |
| 日本語フォント | OS依存(要手動設定) | プリインストール済み |
改ページ制御の違い
/* wkhtmltopdf: 古いプロパティのみ確実に動作 */
.keep-together {
page-break-inside: avoid; /* 旧プロパティ */
}
/* Chromium: 新旧両方対応 */
.keep-together {
break-inside: avoid; /* 新プロパティ(推奨) */
page-break-inside: avoid; /* 旧プロパティ(フォールバック) */
}
FUNBREW PDF API への移行コード
Step 1: wkhtmltopdf の既存コードを確認
典型的な wkhtmltopdf の使い方:
# コマンドライン
wkhtmltopdf \
--page-size A4 \
--margin-top 10mm \
--margin-bottom 10mm \
--margin-left 15mm \
--margin-right 15mm \
--encoding utf-8 \
input.html output.pdf
Step 2: CSS を @page ルールに移行
wkhtmltopdf 時代のCLIオプションを CSS の @page に移す:
/* wkhtmltopdf CLIオプション → CSS @page への移行 */
@page {
size: A4;
margin: 10mm 15mm; /* top/bottom: 10mm, left/right: 15mm */
}
Step 3: FUNBREW PDF API 呼び出しに変換
curl:
curl -X POST https://pdf.funbrew.cloud/api/pdf/generate \
-H "Authorization: Bearer sk-your-api-key" \
-H "Content-Type: application/json" \
-d '{
"html": "<html>...</html>",
"options": {
"engine": "quality",
"format": "A4"
}
}' \
-o output.pdf
HTMLファイルを読み込んでAPIに送る場合:
HTML_CONTENT=$(cat input.html)
curl -X POST https://pdf.funbrew.cloud/api/pdf/generate \
-H "Authorization: Bearer sk-your-api-key" \
-H "Content-Type: application/json" \
-d "{
\"html\": $(echo "$HTML_CONTENT" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))'),
\"options\": {
\"engine\": \"quality\",
\"format\": \"A4\"
}
}" \
-o output.pdf
Python:
import requests
# wkhtmltopdf 時代のコード(移行前)
# subprocess.run([
# 'wkhtmltopdf',
# '--page-size', 'A4',
# '--margin-top', '10mm',
# 'input.html', 'output.pdf'
# ])
# FUNBREW PDF API への移行後
with open('input.html', 'r', encoding='utf-8') as f:
html_content = f.read()
response = requests.post(
'https://pdf.funbrew.cloud/api/pdf/generate',
headers={
'Authorization': 'Bearer sk-your-api-key',
'Content-Type': 'application/json',
},
json={
'html': html_content,
'options': {
'engine': 'quality',
'format': 'A4',
},
},
)
data = response.json()
# PDFのダウンロード
pdf_response = requests.get(data['data']['download_url'])
with open('output.pdf', 'wb') as f:
f.write(pdf_response.content)
print('PDF生成完了:', data['data']['download_url'])
Node.js:
const fs = require('fs');
// wkhtmltopdf 時代のコード(移行前)
// const { execSync } = require('child_process');
// execSync(`wkhtmltopdf --page-size A4 input.html output.pdf`);
// FUNBREW PDF API への移行後
const htmlContent = fs.readFileSync('./input.html', 'utf-8');
const response = await fetch('https://pdf.funbrew.cloud/api/pdf/generate', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk-your-api-key',
'Content-Type': 'application/json',
},
body: JSON.stringify({
html: htmlContent,
options: {
engine: 'quality',
format: 'A4',
},
}),
});
const result = await response.json();
// PDFをダウンロード
const pdfResponse = await fetch(result.data.download_url);
const pdfBuffer = await pdfResponse.arrayBuffer();
fs.writeFileSync('./output.pdf', Buffer.from(pdfBuffer));
console.log('PDF生成完了:', result.data.download_url);
日本語フォント対応の移行
wkhtmltopdf 時代の日本語フォント設定
wkhtmltopdf では日本語を表示するためにOSへのフォントインストールが必要でした:
# Ubuntu/Debianへのフォントインストール
sudo apt-get install -y fonts-noto-cjk
# または wkhtmltopdf に @font-face で指定
FUNBREW PDF では設定不要
FUNBREW PDF には Noto Sans JP がサーバーにプリインストールされているため、HTMLのCSSで font-family を指定するだけで日本語が正しく表示されます:
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<style>
body {
/* Noto Sans JP はプリインストール済み。Google Fonts読み込み不要 */
font-family: 'Noto Sans JP', sans-serif;
font-size: 14px;
line-height: 1.7;
}
h1 { font-weight: 700; }
</style>
</head>
<body>
<h1>日本語タイトル</h1>
<p>ひらがな・カタカナ・漢字・記号(①②③)が追加設定なしで表示されます。</p>
</body>
</html>
オフライン環境や Base64 埋め込みが必要な場合は日本語フォント完全ガイドを参照してください。
よくある移行時の問題と解決策
問題1: 余白が変わった
原因: wkhtmltopdf でCLIオプションで設定していた余白が、CSS @page に移行した際に値が変わった。
解決策: @page { margin: 上下 左右; } の値を確認。物理単位(mm, pt)を使うと予測しやすい:
@page {
size: A4;
margin: 15mm 20mm; /* 上下 15mm、左右 20mm */
}
問題2: フォントが変わった
原因: wkhtmltopdf ではOSフォントを使っていたが、FUNBREW PDF ではCSSの font-family 指定が必要。
解決策: body に font-family: 'Noto Sans JP', sans-serif; を追加する。
問題3: 改ページ位置が変わった
原因: Chromiumはwkhtmltopdfより厳密に break-inside: avoid を適用するため、ページの区切り位置が変わることがある。
解決策: 意図した改ページ制御を明示的にCSSで指定:
/* 改ページさせたくない要素に付ける */
.keep-together {
break-inside: avoid;
page-break-inside: avoid;
}
/* セクション開始時に必ず改ページ */
.new-section {
break-before: page;
}
改ページ制御の詳細はHTML to PDF CSSスニペット集を参照してください。
問題4: レンダリング結果が微妙に違う
原因: ChromiumはwkhtmltopdfよりもCSSを厳密に解釈するため、古いCSSの書き方が正しく動作しない場合がある。
解決策: Playground でHTMLを貼り付けてリアルタイムにPDF出力を確認しながら調整する。
移行チェックリスト
移行作業の完了確認に使ってください:
□ FUNBREW PDF のAPIキー取得
□ CLIオプションの余白設定を CSS @page に移行
□ HTML の文字コードが UTF-8 であることを確認
□ 日本語フォントの font-family 指定を追加
□ 改ページ制御を break-inside / break-before で明示
□ テスト用HTML で PDF出力を確認(Playground活用)
□ 本番HTMLで生成テスト
□ 出力PDFのページ数・余白・フォントを目視確認
まとめ
wkhtmltopdf からの移行で得られるメリットをまとめます:
| 項目 | wkhtmltopdf | FUNBREW PDF(Chromium) |
|---|---|---|
@page CSS |
部分サポート | 完全サポート |
| 日本語フォント | OS依存(要設定) | プリインストール済み |
| CSS Grid/Flexbox | 非対応/部分対応 | 完全対応 |
| セキュリティ更新 | 停止 | 継続提供 |
| ヘッダー/フッター | CLIオプション | CSS @page または API |
| JavaScript実行 | 制限あり | 完全サポート |
移行の複雑さは既存HTMLの品質によりますが、基本的なHTML→PDF変換は APIキーの取得とエンドポイントの変更だけ で完了します。
PlaygroundでHTMLをすぐに試せます。APIの詳細はAPIリファレンス、パフォーマンス最適化はPDF API本番運用チェックリストを参照してください。
関連リンク
- wkhtmltopdf vs Chromium 徹底比較 — 両エンジンの詳細比較
- HTML to PDF CSSスニペット集 — @page・改ページ・余白のCSSレシピ
- PDF 日本語フォント完全ガイド — Base64埋め込み・Google Fonts設定
- Puppeteer から FUNBREW PDF への移行 — Puppeteer移行の手順
- PDF API本番運用チェックリスト — 本番環境でのパフォーマンス最適化
- Playground — ブラウザでPDF出力をリアルタイム確認
- APIリファレンス — エンドポイントの詳細仕様