オウチーノ開発者ブログ

「株式会社オウチーノ」の社員によるブログです。

Web画面を印刷するための基本知識とハック

どうも。オウチーノの田淵です。この記事はくふうカンパニーアドベントカレンダーの8日目として書いています。

2018年10月に、住宅・不動産専門サイトを運営する弊社と、結婚式場紹介口コミサイトを運営するみんなのウェディングが経営統合し、共同持株会社「くふうカンパニー」が設立しました。くふうカンパニーは現在、結婚関連事業、不動産関連事業の他、金融関連事業、デザイン・テクノロジー事業、投資・起業家支援事業を行っています。

はじめに

私は現在、不動産営業支援ツール「くらすマッチ」を開発しています。
くらすマッチは不動産会社・不動産店舗が簡単に物件周辺の暮らしに関する情報を調べることができ、住宅を探しているユーザーニーズに合わせて提案できるツールです。

Webだけでも完結するサービスなのですが、物件情報と合わせて周辺情報の資料をお客様にお渡ししたいというユーザー(不動産営業)ニーズが高いため以下のような印刷機能を開発しました。

  • ブラウザでプレビューできる
  • ブラウザの印刷機能を使って資料を作成できる

開発時にいざ印刷してみると各要素のスタイルが満足に反映されませんでした😓
印刷のスタイルにはブラウザとは一味違う指定が必要だったので、ここで少しまとめてみます。

前提

ターゲットにしたブラウザ

Chrome、IE11、Edge、Firefox
(ツールの特性上、ユーザー数が多いブラウザをターゲットに開発しています)

用紙サイズ

A4 縦

まずは印刷のための基本

  • メディアタイプを知る
    all すべての機器(ブラウザ、印刷 etc...)
    print 印刷プレビュー
    screen ブラウザ
    他にもありますが割愛。
    メディアタイプ(MDN)

  • CSSファイル内では@mediaを使いブラウザと印刷で適用されるスタイルの条件を振り分ける

@media screen { ブラウザだけに適用する }  
@media print { 印刷プレビューだけに適用する }  
@media print, screen { ブラウザ・印刷プレビューどっちにも適用する }  

@media 規則の例(MDN)

  • CSSの読み込み
<link rel="stylesheet" media="all" href="hoge.css" />

メディアクエリにmedia="all" が指定されるようにします。
(HTMLで省略した場合の既定値はallですがHamlなどを使っている場合はデフォがscreenだったりするので要注意)
メディアクエリのついた条件付きのリソース読み込み(MDN)

A4サイズのページを作る

  • ページサイズの指定
    印刷するページのスタイルには@pageで指定します。
    今回はA4の縦ページにしました。
@page {  
  size: A4 portrait;  
  margin: [ページの余白を指定];  
}

@page(MDN)

  • 改ページの指定
    レイアウトされたページごとに印刷したいので指定の位置で改ページするようにします。ページブレイクのCSSプロパティは3種類あるので駆使して理想の位置で改ページさせます。
@media print {
  .pageBreaker {
    page-break-before: always;
  }
}

page-break-before(MDN)
page-break-after(MDN)
page-break-inside(MDN)

ブラウザ仕様が異なる

上述の印刷用のメディアクエリやプロパティを使うことで印刷時にもブラウザと遜色なくレイアウトでき、スタイルも適用することができます。
ですがご想像の通り、ブラウザによって印刷時のスタイルの仕様は異なります。
Web画面として表示するときの仕様ともまた異なります。

一番困るのが、印刷時に背景色が表現されないこと。
ブラウザによって対応方法が違います。

Chrome

背景色を表示するには-webkit-print-color-adjust: exact;を指定する必要があります。
また表示したい背景色には!importantも必要です。

body {
  -webkit-print-color-adjust: exact;
  background: #F4F4F4 !important;
}

IE11

背景色を表示するにはユーザーがブラウザの印刷プレビュー上のページ設定で背景の色とイメージを印刷するのチェックボックスをONにしないと表示されません😓

Edge

Edgeは背景色が表示されません。
(」゚O゚)」< Edgeは背景色が表示されません。
方法を探し回りましたが、↓↓の回答に行き当たりました。マイクロソフトサポートの公式回答のようです。
Windows10 EdgeでWeb上の画面を印刷すると背景の色や罫線が印刷できません。

まことに恐れ入りますが、Microsoft Edge には Internet Explorer のように背景を印刷する設定箇所がありません。 そのため、背景を印刷される場合は IE をご利用頂くようお願いいたします。

現在でも設定できそうな箇所は見当たりませんでした😭

Firefox

背景色を表示するには表示したい背景色に!importantが必要です。

background: #F4F4F4 !important;

また、ユーザーがブラウザの印刷設定でアピアランス > 背景色をプリントのチェックボックスをONにしないと背景色は表示されません😓

Edgeの背景色問題をどうしたか

背景色background-colorが表示されないEdgeでもborderや画像は表示されるようです。
background-imageを指定してbackground-colorの代替とする手法がWeb検索するとヒットしましたが、カラーごとの画像を用意するのは変更に弱い印象を受けました。

当時は開発中のためデザイン的にも容易に変更できるほうが望ましかったのです。
幸いレイアウトも単純だったためborder-colorを利用して背景色を表現することにしました。

一例としてタイトル行に背景色をつける例。

HTMLとCSSはこんな感じ。

<div class="titleBackground"></div>
<h3>
    <span>No</span>
    <span>コンビニ</span>
    <span>距離</span>
</h3>
@media print {
  .titleBackground {
    border-bottom: 20px solid #272736 !important;
    margin-bottom: 10px;
  }

  h3 {
    height: 20px;
    font-size: 8px;
    margin-top: -30px;
  }
}

背景色の代わりにborder-bottomの線幅を欲しいサイズに指定しています。
その下に用意したタイトルになるテキストをネガティブマージンでborderに重ねてタイトル行の背景色を表現しました。

Googleマップからマーカーがはみ出る問題

サービスの特性上、周辺情報を表示するためにマップは不可欠です。当然、紙面にもマップが印刷されます。
今はGoogle mapを利用しています。
スーパーやコンビニ、公園、保育園などの周辺施設の位置をカスタムマーカーで表現しています。

地図の縮尺によってはレイアウト内に収まらないマーカーが出てきます。当然、Googleマップではレイアウト外になったマーカーは表示されない動作になります。

これがIE11では動きが異なります。
レイアウト外になったマーカーがマップ外に表示されてしまいます。
印刷時にもマップ外の領域に突然マーカーが表示されている状態になるので困ります。

Google mapはデフォルトで下記のようなマークアップがされています。
いろいろ試したところ、class="gm-style"のdiv要素にoverflow: hiddenを指定してあげることでこの問題は解消できます。(しかも他のブラウザでの悪影響は発生しません)

<div class="map" style="position: relative; overflow: hidden;">
  <div style="height: 100%; width: 100%; position: absolute; top: 0px; left: 0px; background-color: rgb(229, 227, 223);">
    <div class="gm-style" style="position: absolute; z-index: 0; left: 0px; top: 0px; height: 100%; width: 100%; padding: 0px; border-width: 0px; margin: 0px;">
      <div tabindex="0" style="position: absolute; z-index: 0; left: 0px; top: 0px; height: 100%; width: 100%; padding: 0px; border-width: 0px; margin: 0px; cursor: url(&quot;https://maps.gstatic.com/mapfiles/openhand_8_8.cur&quot;), default; touch-action: pan-x pan-y;">
      <div style="z-index: 1; position: absolute; left: 50%; top: 50%; width: 100%; transform: translate(0px, 0px);">
      <div style="position: absolute; left: 0px; top: 0px; z-index: 100; width: 100%;">
      <div style="position: absolute; left: 0px; top: 0px; z-index: 0;">
<以下割愛>
.gm-style {
  overflow: hidden;
}

まとめ

今後も細かい調整や各OS、各ブラウザへの対応をブラッシュアップしていきたいと思います。

Web画面をPDF化せずに印刷するにはブラウザの印刷機能を使うしかなく、JavaScriptからも制御できない部分が非常に多いです。
ページごとのヘッダー・フッター表示などユーザーの印刷設定による部分が大きいので、技術的にできることは少ないがユーザーがストレスなく印刷できるための操作説明などをうまく見せることも必要かと感じました。

普段、Web画面と戦っているエンジニア・デザイナーが画面を印刷したいと言われたときに困らないよう、基本的なところをまとめてみました。

明日(9日)は@ken1flanさんの「ニャーQL勉強会(エンジニアじゃないひとたちとやったSQL勉強会)」です。