CSSのbox-shadowが印刷時に異なるレンダリングになる問題を少しだけ深掘りする
CSSのbox-shadowは、画面上では意図通りに表示されていても、実際に印刷やPDF出力を行うとまったく異なる見た目になることがあります。しかもDevToolsのprintエミュレーションでは再現しないという厄介な問題で、少しハマったので整理しておきます。
発見した現象
SVGアイコンを含むボタン要素に以下のようなスタイルを設定していたときのこと。
.icon-button { display: inline-flex; align-items: center; background: #fff; border: 1px solid #c5d8f0; box-shadow: 0 5px 10px 0 rgb(140 180 231 / 20%);}
これをmacOS上のChrome(v145系)にて印刷用スタイルのデバッグ中、以下の3つの環境で異なるレンダリング結果が表示されるという状況が発生。
| 環境 | 結果 |
|---|---|
| 画面表示 | 薄い青色のドロップシャドウ(意図通り) |
DevTools @media print エミュレーション | 同上 |
| 実際の印刷プレビュー / PDF出力 | 青色の背景が塗りつぶされた表示 |
画面では綺麗な薄い影が表示されるのに、実際の印刷プレビューでは影の部分が不透明な青い塗りつぶしのようになってしまう、という少し不思議な現象でした。
なぜDevToolsエミュレーションで再現しないのか
DevToolsの「Rendering」パネルから@media printをエミュレーションできますが、この方法では今回の問題を再現できません。
DevToolsのprintエミュレーションはあくまでprintメディアタイプでCSSを評価するだけの機能で、実際の印刷やPDF出力の描画結果を再現するものではありません。@media printでbox-shadow: noneが効いているかの確認には使えますが、描画がどう変わるかはCmd + P(WindowsではCtrl + P)の印刷プレビューで見るしかありません。
画面表示と印刷で描画経路が異なる
画面表示ではブラウザの通常の描画パイプラインが使われますが、印刷やPDF出力ではこれとは別の印刷向け描画経路を経由します。具体的な実装はブラウザやOSによって異なるものの、画面表示とは別の処理を通る以上見た目が変わりうるのは避けられません。
印刷時にbox-shadowが崩れる原因として考えられること
根本原因を特定するにはブラウザの内部実装を追う必要がありますが、それは中々に時間がかかるのでここでは考えられる仮説を挙げておきます。
仮説1: 透明度(alpha)の処理差異
今回のスタイルではrgb(140 180 231 / 20%)と20%のアルファ値を使っています。印刷やPDF出力の過程で、この透明度やぼかしの合成が画面表示とは違う扱いになっている可能性があります。
- 透明度のフラット化: PDF変換時に透明度を解決する際、背景色との合成結果が画面と異なる
- ぼかし処理の差異:
box-shadowのぼかし(blur)がPDF上で異なるアルゴリズムで処理される
仮説2: 印刷向け描画経路での変換差異
前述の通り、印刷やPDF出力では画面とは別の描画経路を通ります。この過程でbox-shadowのような装飾的プロパティの変換に差異が生じ、影が塗りつぶしのように見えてしまうというパターン。
実際のプリンターに出力する場合は、ドライバーや色空間変換(sRGBからCMYKなど)の影響も加わりますが、Chromeの印刷プレビューや「PDFとして保存」で再現するなら、ブラウザ側の描画経路が主な要因と考えられます。
他に影響を受ける可能性のあるプロパティ
今回はbox-shadowで遭遇しましたが、印刷時の描画経路の違いで影響を受けそうなプロパティは他にもあります。
| プロパティ | 印刷時の影響(推測) |
|---|---|
text-shadow | box-shadowと同様の問題が発生する可能性あり |
filter: drop-shadow() | box-shadowとは描画対象が異なるため、印刷時の挙動も異なる場合がある |
backdrop-filter | 印刷時にサポートされない場合がある |
opacity | 透明度の処理差異により、画面と異なる結果になる可能性がある |
あくまで推測なので、実際に問題になるかはプロパティごとに確認してみてください。
解決策
仕様に基づいた根本原因の特定はできていませんが、解決策自体はシンプルで印刷用のメディアクエリでbox-shadowを無効にするだけです。
@media print { .icon-button { box-shadow: none; }}
そもそも影の視覚効果は印刷物では不要なケースがほとんどだと思いますので、割り切って消してしまうのが一番です。(インク消費も抑えられます)
デバッグ時の注意点
印刷関連のスタイルをデバッグする際は、以下の点に注意が必要です。
- DevToolsのprintエミュレーションを過信しない:
@media printのCSS適用確認には有用だが、描画結果の最終確認にはならない - 実際の印刷プレビューで確認する:
Cmd + P(WindowsではCtrl + P)で印刷プレビューを開いて、実際のレンダリング結果を確認する - PDF出力でも確認する: 「PDFとして保存」を使ってPDF出力した結果も確認しておくと安心
まとめ
box-shadowは画面・DevToolsエミュレーション・実際の印刷でそれぞれ描画結果が異なることがあり、DevToolsのprintエミュレーションでは再現できないのが厄介なところです。原因としては透明度の処理差異や印刷向け描画経路の違いが考えられますが、確実なのは@media printでbox-shadow: noneを指定してしまうこと。印刷スタイルのデバッグでは、DevToolsだけで安心せず必ずCmd + Pで実際の印刷プレビューを確認するのが大事です。