web帳票PDFのスタイリング方法
web帳票といえばQiitaのこの記事。
そろそろ真面目に、HTMLで帳票を描く話をしようか
実に3年前、業務システム受託開発がメインの企業でたった一人のデザイナーをやっていたとき、まさに「もうHTMLで帳票作ってmedia=”print”で出せるようにしたらいいんじゃないですか?」という提案をしようとしていた私にとってタイムリーすぎた記事でした。
まさか3年越しで本当に実務でweb帳票を扱うことになろうとは思いませんでした。
Laravelで作られている内製業務システムで、見積書や発注書、納品書などをPDFで出力するという機能があり、その印刷用スタイリングを任されました。
SnappyPDFというライブラリがあり、PDF出力が簡単にできるそうなのですが、これが若干クセがありました。
Snappy PDF
ライブラリの導入についてはエンジニアさんがやってくれていて環境がすでにできていたのでここでは扱いません(よくわかりません)
この記事では、SnappyPDFの利用を前提とした、CSSでの帳票スタイリングの注意点やコツを紹介していきます。
まずは、CSSのルール
今回の業務システムのweb帳票は、ブラウザ上でのプレビュー表示は行われません。
「PDFをダウンロード」みたいなボタンがあってポチッとしたら出力されたファイルがダウンロードされます。
そこで、あくまでも印刷用としてブラウザ表示のことは考えずにスタイリングしていきました。
- px,em,remなどの環境に依存する値を使わない
- 単位は現実世界の絶対値であるmm、ptを使用する
ちなみにptはフォントサイズの単位で、1pt = 0.35mmです。
慣れない人はmmで計算して指定してもOK。
開発用レイアウトは@media screenで記述
さきほどの記事にもありましたが、開発中はブラウザ確認しやすいように@media screenでレイアウトをわけて記述しておき、リリース時に消すのがおすすめです。(なぜ消さなければならないか理由は後述します)
[code lang=”css”]@media screen {
body {
width: auto;
background: #ccc;
}
.wrap-content-pdf {
margin: 0 auto;
padding: 10mm;
background: #fff;
box-shadow: 1px 1px 4px rgba(0,0,0,0.4);
}
}
[/code]
CSSの最後にこんな感じで書いておくと印刷プレビューぽい見た目になるのでウィンドウサイズに関係なく開発しやすくなります。
A4 = 240mmという謎ルール
本来ならば、@pageを使って印刷サイズやマージンを指定するべきなのですが、Safariはそもそも対応していません。IE,Chrome,Firefoxもsizeプロパティをサポートしていません。(2018年11月現在のことなので将来もしかしたら対応されるかもしれないのでCan I useで確認しましょう)
クs…そういうわけでコントロールできない部分なのであとは印刷して確認してみるしかありません。
通常A4サイズは幅210mmなんですが、bodyをmargin,padding抜きの210mmで設定するとなぜか紙面が余ります。
240mmにするとちょうどいいんです。
おそらくなのですが、SnappyPDFの処理の中で親切心で印刷用の余白がついているのではないかと思います。
bodyにmarginを持たせない
前述のとおりブラウザで勝手に余白がつくようになっているのでコンテンツ本体の余白はCSSで設定する必要がありません。
ただし開発中はレイアウトがわかりにくいので、前述のようにコンテンツに対してpaddingをつけておくと実物に近いイメージになるので捗ります。
[code lang=”css”]@media screen {
.wrap-content-pdf {
padding: 10mm;
}
}
[/code]
position:absolute;などで紙のフチを基準に配置している要素は当然ずれます。
そのあたりお察しください。
背景印刷ができるように設定する
Chromeではbackground-imageだけでなく、background-colorも印刷されません。
カラー/モノクロ、背景色の濃さに関係なく常に背景を印刷する設定を記述しておく必要があります。
[code lang=”css”]body {
-webkit-print-color-adjust: exact;
}
[/code]
改ページの制御
コンテンツのボリュームが変わる帳票では、改ページの制御をする必要があります。
table(表)の行の途中で切れてしまったり、枠線で囲まれたsectionが途切れたりするのを避けたいときは、対象の要素にpage-breakを設定しましょう。
[code lang=”css”]section {
page-break-inside: avoid;
}
[/code]
- page-break-before:対象の要素の手前
- page-break-inside:対象の要素の途中
- page-break-after:対象の要素の後
- avoid:その箇所での改ページを避ける(insideのみ有効)
- always:その箇所では常に改ページする
もしも下記のように設定したとき、後ろにコンテンツがなければ改ページされません(ブランクページは印刷されなくて済みます)
[code lang=”css”]table {
page-break-after: always;
}
[/code]
1ページに連続して複数の表を印刷したくない場合などに使える方法です。
といっても、実際、業務で必要だったのはpage-break-inside: avoid;だけで、これさえあればだいたい望んだ通りになります。
SnappyPDFのクセ
クライアントPCにフォントがなくてもOK
SnappyPDF自体に日本語フォントをインストールしておけば、ヒラギノやメイリオが使えます。
CSSでいつも通りfont-familyを設定するだけでOK。
@media screenが採用される
あくまでもwebブラウザ上の表示からPDF変換するらしいです。
そのため、@media printと@media screenで切り分けるということができません。
@media screenのスタイルが効いた状態で出力されてしまうので、開発中のプレビュー用スタイルはリリース時に消さないといけないというわけです。
flexが使えない
display:flex;によるレイアウトが効かず崩れます。SnappyPDFの処理の中で解釈されないようですね。@media screen環境での確認中には気づきにくいので注意が必要です。
display:inline-block;代替手段②
display:table;
display:table-cell;
レイアウトしたい要素とそのHTML構造によるので、適した方を使用しましょう。
まとめ
webブラウザ上の表示をそのままPDFに変換するということで、多少のクセはあるものの、それさえ理解してしまえばあとは通常どおりスタイリングするだけなので、かなり楽でした。
たいていの場合、帳票はテキストと表のシンプルな構造なので、組み方自体に悩むことはほとんどありませんね。
今後の課題としては、「モバイルでPDFダウンロード→プリンタに送信して印刷」といった活用をするには?そもそもモバイルでweb帳票を表示するときの最適解は?などなど気になるところです。