画像読み込みの最適化の副作用:「印刷時のみ出力する画像が表示されない」問題とCSSによる解決策
日々の運用の中で、数年前に実装した機能がブラウザのアップデートに伴い予期せぬ挙動を示すことがあります。今回は、Webページからの領収書印刷機能において「印刷時のみ特定の画像(社判など)が表示されない」というトラブルに直面した際の調査と解決策を共有します。
課題(Situation/Task)
受注情報から領収書を印刷する機能において、「ブラウザから印刷しようとすると、社判などの一部の画像が出力されない」という現象が発生しました。画像URLに直接アクセスすると正常に表示されるため、リンク切れではありません。
該当の画像部分は、以下のようにコーディングされていました。
<div class="visible-print" style="margin-left:70%">
Issued by:<img src="example.png" alt="社判" />
</div>
親要素の visible-print クラスは、画面表示時はCSSで display: none !important; となっており、印刷時(@media print)にのみ表示される仕様です。
欠落の原因:ブラウザの画像読み込み最適化
調査の結果、近年のモダンブラウザ(特にChromeやEdgeなどのChromium系)における画像読み込みの最適化が原因であることがわかりました。
以前のブラウザは display: none の内部にある画像であっても、ページロード時にある程度画像の取得を行っていました。しかし現在では、パフォーマンス向上のため「画面上に表示されていない要素内の画像は、実際に表示されるまでネットワークリクエストを保留する」挙動が一般的です。
そのため、以下の流れで画像が欠落(白抜け)してしまいます。
- 通常の画面描画時、
visible-print内の画像は読み込まれない。 - ユーザーが「印刷」ボタンを押下し、プレビュー画面が起動する。
- 印刷用CSS(
@media print)が適用され、ここで初めて画像の読み込みリクエストが発生する。 - 画像のダウンロード完了より先に印刷用の描画処理が終わってしまい、プリント上に画像が反映されない。
ChromiumのIssue Tracker(Issue 40702255)でも、「遅延画像が印刷プレビューの生成に間に合わない」という問題が議論されています。
なお、同じ visible-print 内にあっても、共通ヘッダーなど画面の別箇所でも使用されているロゴ画像などは、既にブラウザにキャッシュされているためプレビュー起動時に即座に描画されていました。今回問題になった画像は「印刷領域にしか存在しない画像」だったため、顕著に影響を受けていました。
解決策(Action)
この問題に対する根本的なアプローチは、「印刷プレビューが開く前に、あらかじめ画像を読み込んで(キャッシュして)おくこと」です。
画面のロード時に確実にキャッシュさせるため、display: none を使わず、画面上には見えない形でダミーの画像タグを配置する手法をとりました。具体的には、テンプレート内の visible-print のブロックとは別の場所(コンテンツ領域の最下部など)に、以下のようなHTMLを追加します。
<img src="example.png" style="position: absolute; width: 0; height: 0; overflow: hidden; opacity: 0;" alt="" aria-hidden="true" />
この記述により、ブラウザは「画面上に存在する要素」としてページを開いた時点で画像をダウンロード・キャッシュします。
結果(Result)
上記の手法を導入した結果、ページを開いた時点で対象の画像がブラウザにキャッシュされるようになりました。
これにより、ユーザーが印刷プレビューを開いた際、通信のラグを生じさせることなく即座に画像が描画され、白抜けの不具合を完全に解消することができました。ブラウザの最適化技術は日々進化していますが、それが過去の実装に影響を与えるケースもあります。同様の現象でお困りの方の参考になれば幸いです。