ブラウザでの画面表示と印刷の描画差異に関する実践的考察
おごちゃん
相変わらずHieronymusをいじっております。
やりたかったことはほぼ完成し、ちゃんと数字の合う決算書も作れるようになりました。 これで、会計システムの必要最低限のことは実装されました。
元々、帳票の部分はExcel表を出していたのですが、やっぱり「紙」イメージのものが出た方が良いので、全部Playwriterを使ったPDF出力に書き換えました。 これが結構難物で、結構面倒臭いことでしたが、まぁ面倒臭いだけで技術的に凄い難しいということはありません。
で、とりあえずHTMLを作ってPDF化をPlaywriterを使って… とやってみたのですが、ページの長さがどうも合いません。 ChatGPTとごちゃごちゃ相談するのですが、「設定忘れパラメータ」の類を設定しても合ってくれません。
しょうがないので、画面に出したもの(これはぴったり合ってる)をブラウザの印刷しようとすると、よく見たらこれも合っていません。
そこで表題のような話です。
背景
元々Hieronymusの「帳票」はExcelでして… って話は前回したとおりです。
それでは都合の良いことも不便なこともあるので、PDFにするよーというのが前回の話です。 あの時は見積書とか請求書の話だったのですが、どうせなら全部やっちゃえということで、ExcelでやっていたものをHTML化しました。 これをPDFにして出力すればいいわけですから。
ということで、画面レベルまでは動くようになりました。 もちろん、A4 1ページになるようなスタイルシートを作りました。 後はこれをハードコピーするなりPDF化するなりすれば完成です。
で、実際にPDFにすると、なぜかページに余白ができます。
ちなみにスタイルシートを抜粋するとこんな感じ
.page {
width: 210mm;
height: 297mm;
max-width: 100%;
margin: 0mm auto;
padding-left: 17.8mm;
padding-top: 2mm;
background: white;
//box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
transform-origin: top;
position: relative;
break-after: page;
overflow: hidden;
...
@page {
margin: 0;
size: 210mm 297mm;
}
コメントにしてあるbox-shadow
を有効にすると、ページの区切りが出てくれます。
問題
問題は、width, heightをちゃんとA4の寸法に指定していても合ってくれないということです。 もう少し正確に言うと、ブラウザで見た時には合うのですが(box-shadowがいい感じに見えました)、PlaywriterでPDF化した時やブラウザの「ページを印刷」をした時も、ページの後に余白がついているということです。
当初はPlaywriterでPDFにした時に気がついたので、PDF化した時の問題かと思っていたのですが、確認しているうちに「ページを印刷」した時も同じようになることに気がつきました。
この時、ブラウザもPlaywriterも、余分な余白やページヘッダの類を勝手に入れないようにしてあります。 つまり、本来であればまるっとコンテンツを印刷するはずの設定になっています。
解決
この部分はChatGPTにまとめてもらったので、それを引用します。
✅ 背景と問題意識
Webブラウザを使ってA4帳票(210mm × 297mm)を画面に表示し、そのまま印刷またはPDF出力しようとすると、
画面上はぴったりなのに、印刷では下に不自然な余白ができるという問題に直面することがある。
一見、用紙サイズやCSS指定に誤りがあるように見えるが、これは主に 「ブラウザの画面表示」と「印刷時の描画ロジックの違い」 によって生じる。
✅ 根本原因:画面と印刷は描画モデルが異なる
📺 通常の画面表示(@media screen
)
- DOMの位置やサイズはそのまま描画される
transform: scale()
などのCSS変形も見た目だけに作用- 親要素の
overflow: hidden
などで切り取られやすい
🖨️ 印刷時の描画(@media print
/ PlaywrightのPDF)
- ページという物理的単位を意識して再レイアウトされる
transform: scaleY()
なども「見た目」だけでなく、描画エリアの計算に影響- ページをはみ出さないように、自動でスケーリングがかかることがある
✅ よくある症状と誤解
現象 | 誤解されがちな原因 | 実際の要因 |
---|---|---|
印刷時に下が空く | .page の高さが足りない? |
内容が縦方向に自動で縮小されている |
横はぴったりだが縦に余白 | CSSが間違ってる? | ブラウザ印刷エンジンの内部スケーリング |
画面では下まで表示されるのにPDFでは切れてる | HTMLのミス? | scaleY() が画面でははみ出し、印刷では再レイアウトされて収まる |
✅ 解決策:印刷時にのみ scaleY()
で縦方向補正を加える
.page {
transform-origin: top;
}
@media print {
.page {
transform: scaleY(1.076); /* 環境によって調整(1.07前後) */
}
}
scaleY()
によって、印刷エンジンが自動で縮める挙動を打ち消す- 画面には影響を与えず、印刷だけで補正が効く
✅ Playwrightはこの挙動の「自動化ツール」にすぎない
await page.pdf({
width: '210mm',
height: '297mm',
printBackground: true,
margin: { top: '0mm', bottom: '0mm', left: '0mm', right: '0mm' },
preferCSSPageSize: true,
displayHeaderFooter: false,
scale: 1 // 実質効かないが指定はしておく
});
Playwrightはこの印刷処理を自動化するだけで、
根本的な描画差異(画面 vs 印刷)を埋めてくれるわけではない。
✅ 結論と実践指針
- 画面表示と印刷結果は同一にならない前提で設計する
- 印刷時は独自の補正が必要(特に縦方向のスケーリング)
- scaleYを
@media print
でのみ適用して帳票の実寸出力を確保する - Playwrightを使うなら、この補正ロジックも含めて実装しておくこと
まとめ
この問題をあまり深追いするつもりはありませんが、簡単に言ってしまえばブラウザを表示で使う時と印刷で使う時は違うということです。 Playwriterも中身はブラウザですから、この辺は全く同じです。
スタイルシートで何も考えないで指定したdimensionは、ブラウザが表示する時のものであって、「印刷」動作をする時のものではないということです。 「印刷」は単に表示されているものを印刷形式に変換するだけではなくて、その過程であらためてレンダリングをしています(画面のリロードがあるかどうかは別の話です)。 そして、そのレンダリングは「印刷」のために行われている… と考えた方が今回のような問題を考える時には早道でしょう。
そこで今回の私のところでは縦方向だけ1.076倍するということで解決ができましたという話です。 この1.076という絶対値そのものにはあまり意味がないと思いますが、「印刷」をする時にはこれだけ縮んでレンダリングされている(いた)という意味です。
わかってしまえばどうってことないのですが、なかなか気がつきませんでした。 何しろこの辺のことはいじるパラメータもいじる箇所も多過ぎですからね。 同じような問題でハマっている人の助けになれば嬉しいです。
あと、このパラメータ調整には、
<div style="position: absolute; bottom: 0; left: 0; right: 0; height: 3mm; background: red; text-align: center;">
下端ライン
</div>
こんなのを書いておくと、「実際のベージの下端」が可視化されるので便利です。
box-shadow
でもいいと言えばいいんですが、box-shadow
自体が邪魔になる可能性も捨て切れないので、内側に描いておくといいのです。