Chienomi

プリンタブルウェブのすすめ

プログラミング::web

プリンタブルウェブ、それはつまり「印刷できるウェブページ」だ。

現代において印刷向けフォーマットはほぼPDFに集約されている。 PostScriptプリンターはもはや現役ではなく、またDVI形式を直接扱うこともない。 一方でプリンターは(専用のラスタライズド言語だけでなく)PDFを直接サポートすることも増えている。

そして、そのPDFの前段となるテキストドキュメント1というと、TeXか、あるいはMS Wordあたりが主だろう。

そこに新たな(というほど最近の話でもないが)選択肢となっているのがHTML文書だ。 CSSは初期から印刷向けのプロパティが存在したが、それらをサポートしているのはOperaくらいのもので、ほとんど機能していなかった。 だが、最近はChromiumやFirefoxでも印刷関連プロパティがサポートされ、またプロパティの追加もあってかなり使えるようになってきた。

これは「印刷用HTML」を作る話だが、ウェブブラウザに印刷機能があることと、CSSメディアクエリの存在によってウェブページにおいてもウェブブラウジングと印刷の両方を兼ねることが可能だ。

だが、現代のウェブサイトの多くは印刷が困難だ。 印刷が想定されていないというのもあるし、印刷を含めた非スクリーンの存在を蔑ろにしているためでもある。

プリンタブルウェブの基本

実のところプリンタブルウェブというのはそれほど特別なものではなく、単純なアクセシビリティの一環であるといえる。

例えば単純な(CSSやレイアウトブロックなどを含まない)HTMLドキュメントをウェブブラウザの機能で印刷すれば、問題なく印刷できるだろう。 ただし、その仕上がりはTeXと比べるといくらか物足りないものではあるが。

話を単純化するために、Pandocを使うことを想定しよう。

まずは単純なPandoc Markdownドキュメントを作る。

---
title: 文書のタイトル
---

# 序

これは序文。

# 第一章

これは第一章の段落。

これは第一章の段落。

そして生成する。

pandoc -t html5 -s -o out.html

PandocでCSSを指定しないと、今はそこそこちゃんとしたCSSが盛り込まれるようになっているので、「単純なHTMLファイル」とは違うが、問題なく印刷できる(しかもクオリティもそれなりに高い)ものが仕上がるはずだ。 これは、Pandocのデフォルトが印刷を考慮したCSSになっているためである。

ただ、これだと前提がおかしくなってしまうので、HTMLテンプレートを使ってさらにシンプル化してみる。

<html>
  <head>
    <title>$title$</title>
  </head>
  <body>
    <article>
      $body$
    </article>
  </body>
</html>

で、こんな感じ。

pandoc --template template.html -t html5 -s -o out.html

これで「プレーンなHTMLドキュメント」は美しくはないが、それなりに読める印刷が可能であることが分かっただろう。

「美しく仕上げる」ことは置いておくとして、まずは「ちゃんと印刷できるウェブページ」への道である。

基本的には「きちんと構造化された文書である」ということが重要になる。 レイアウトブロックやナビゲーションブロックがあっても良いのだが、ちゃんと分離されてないと印刷に向かないものになる。

また、大前提としてドキュメントはそれ自体で完結したものである必要がある。 JavaScriptを使ってドキュメントをロードする、というような形式は論外だ。 そのようなことをすると非スクリーン環境におけるアクセシビリティを著しく低下させてしまう。

ナビゲーションブロックとフッターを持つ構造だと次のように。

<html>
  <head>
    <title>$title$</title>
  </head>
  <body>
    <nav>
      <!-- ... -->
    </nav>
    <article>
      $body$
    </article>
    <footer>
      <!-- ... -->
    </footer>
  </body>
</html>

あるいは左右にレイアウトするためにナビゲーションブロックと本文ブロックがフレックスボックスになっているとするとこんな感じ。

<html>
  <head>
    <title>$title$</title>
  </head>
  <body>
    <div>
      <nav>
      <!-- ... -->
      </nav>
      <div>
        <article>
          $body$
        </article>
      </div>
    </div>
    <footer>
      <!-- ... -->
    </footer>
  </body>
</html>

本文はどこを抜き出せばいいか、というのが明確であるべきで、スクリーン上の話ではなく、HTMLとして各ブロックが独立してフォーカスできるようになっている必要がある。 ちなみに、これはリーダービューへの対応としても良い結果をもたらす。

また、ドキュメントは(Pandocが生成するように)ドキュメントとしてきちんと構造化されているべきだ。 h1からh6のヘッダーによって適切に章立てされており、pによって本文段落によって形成されているというものであるべき、ということだ。 このようなドキュメントとしての構造から逸脱しないようにきちんとした構成にする。

さて、ここからエッセンシャルなCSSだ。 例えば次のようなHTMLだとする。

<html>
  <head>
    <title>$title$</title>
  </head>
  <body>
    <header id="DocumentTitle">
      <h1>$title</h1>
    </header>
    <div id="MainContainer">
      <nav id="SiteNavigation">
      <!-- ... -->
      </nav>
      <div id="MainContent">
        <nav id="TopicPath">
          <!-- ... -->
        </nav>
        <nav id="TOC">
          $toc$
        </nav>
        <article id="MainArticle">
          $body$
        </article>
      </div>
    </div>
    <footer id="SiteInfomation">
      <!-- ... -->
    </footer>
  </body>
</html>

この中で印刷すべき要素はタイトル, TOC, 本文であるとする。

レイアウトの問題(この場合、MainContainerがflex containerである)に関しては、

@media screen {
}

の中に入れることで、印刷に影響が出ないようにする。

あとは、表示したくないところを消していくだけでよい。

@media print {
  #SiteNavigation, #TopicPath, #SiteInfomation {
    display: none;
  }
}

セクショニングコンテンツを含めてブロックはページ全体の幅を持ち、縦に並ぶので、要素の登場順に並んでいくだけだ。 これだけで印刷と両立するサイトができる。

印刷向けのデザイン

では、「美しい印刷ページ」に向けた話をしていこう。 メディアクエリを使って印刷向けに仕上げれば良いということはすでに明確なので、あとはプロパティを設定していくだけだ。

別にTeXが正解というわけではないのだが、格調高い文書(論文とか)で見慣れたものでもあるので、TeXの習慣・デザインをお手本と考えていこう。

ウェブでも本文フォントはどちらかといえば明朝体のほうが読みやすいのだが、以前の記事で述べたようにスクリーンに明朝体があまり適さない要素があり、安易に明朝体を採用しづらい。 Chienomiの場合は本文が読み物というより情報であるため、流し読みやすい明朝体ではなく、ゴシック体を採用している。 だが、それでも印刷になると、慣れの問題もあるが、やはり本文は明朝体のほうが良い。技術書も多くは本文は明朝体だろう。

で、どこでどう指定するべきかなのだが、ちゃんと構造化されていれば、次の形で良い。

@media print {
  body, article p strong {
    font-family: sans-serif;
  }

  article p, article ul, article ol, article dd {
    font-family: serif;
  }
}

明朝体になる範囲がかなり狭いように見えるが、基本的に本文はarticle要素の中の段落になるので、これでTeXと同じような配分になる。 strongは強調の意味でもゴシック体にしたいので、article p strongをセレクタに加える。

表をLaTeX風にするのはこんな感じ。

table {
  border-collapse: collapse;
  border-top: #000 2px solid;
  border-bottom: #000 2px solid;
  border-left: 0px none;
  border-right: 0px none;
}
thead {
  border-bottom: #000 1px solid;
}
tr th td {
  border: 0px none;
}

印刷時はスクリーンとはサイズの単位体系が異なることに注意が必要だ。 スクリーンの場合は基本的に96dpiであるとして、1pt = 1.333pxに換算される。 逆に言えば、1pxは約0.75ptになる。 だが、実際は1未満のピクセルは基本的に表現できない(条件によっては色の混ぜ合わせで表現されることもある)。そのため、切り捨てが発生する。

ここにスクリーンのスケーリング(UIスケーリングもそうだし、ウェブブラウザ側の倍率もそう)がかかり、物理ピクセル数が決定される。 最終的には物理ピクセルに換算するしかなく、またpxも相対化されて物理ピクセルへの換算に対象になっている。

この96dpiの換算によってpt, inch, mmといった単位はpxに変換され、それがスケーリングによってさらに物理pxに換算される。

一方、印刷時はpxという単位を物理スケールに換算する必要がある。これは単純に、96dpiであるという前提のもと、0.75ptへと換算される。物理寸法の絶対単位は印刷時はそのまま絶対単位として機能し、相対単位は物理スケールにおける相対単位として機能する。

比率が変化することはないが、ディスプレイ上では気にならない無理のある物理寸法は印刷時に無理な大きさになってしまう。

もちろん、換算を前提に指定してもいいし、少ないpx単位(1pxとか)はpxを使っても良いが、印刷向けのCSSでは物理寸法を使うほうが良い。

さて、ここまで説明した上で、「印刷時は基準フォントサイズを決める必要がある」という話をしよう。 基本的に日本語の文書で親しまれているのは5号判、つまりは10.5ptである。 これは日本語における慣習であるため、ブラウザ任せにするとあまりうまくいかない。なので、指定する。

@media print {
  body {
    font-size: 10.5pt;
  }
}

h1などのフォントサイズは%em指定すると設定の共有が可能。 前提として、スクリーンであろうが使うべき単位を適切に使い分けていること。

ページレイアウト(余白など)は基本的にウェブブラウザまかせでいい感じになる。 以前はみっちみちだったが、現在はもうあまり調整しなくていいので、全体的にスクリーンと比べかなりコンパクトなCSSになる。

Chienomiの印刷用CSS

Chienomiは情報というより学習という色合いのある記事がそれなりにあり、時間をかけて読み込まれる可能性がある。 もちろん、現代においてはスマートフォンやタブレットを使うという人も多いだろうが、あえて紙の本で学習する人も少なくない世の中で、印刷して読みたいという要望は潜在的にはそれなりにあるだろう。 私もZshのマニュアルやDeleGateのマニュアルを印刷して読み込んだりしたものだ。

こうした理由もあり、Chienomiはそれなりに印刷用CSSに気を遣っている。 とはいえ、デザインリニューアルに追従していないといったこともあったりするのだが。

基本的にはここで紹介したように、印刷に適した要素に絞り込み、そのデザインを印刷向けに仕立てている。 基本はLaTeX的なデザインであり、実際にTeXLive Japaneseで組んだものを参考にして書いた。

色については、テキストドキュメントをカラー印刷はしたくないだろうから、グレースケールのデザインに直している。 グレースケール印刷すれば同じではあるのだが、コントラストを意識したほうが最適化できるので、グレースケールで作り込むほうが良いと思っている。

フォント指定に関しては説明とは逆で、bodyにserifを指定し、sans-serifを使う要素を指定している。 これは、説明したものより厳密なもので、指定すべき要素がだいぶ多くなる。 また、印刷用明朝体だが、ちゃんと指定しているケースが少ないことから、ある程度「より良い」本文明朝になるように具体的に指定が入っている。

  body {
    font-family: "UDTypos510 Std", "Yu Mincho", "YuMincho", "Source Han Serif", "Source Han Serif JP", "Noto Serif JP", "BIZ UDPMincho", serif;
    font-size: 10.5pt;
  }

コードブロックにbox-shadowが設定されているのは、Listingsリスペクトだ。

検出できるわけではないので感覚的な話だけれど、Chienomiが印刷に適しているというのは繰り返し言っていかないと忘れられてしまう気がしている。 印刷してKindleで読むという手もある。

まとめ

「ウェブページを印刷する」というニーズは限定的なものではあるが、そのサポートは決して難しくない。 HTMLの基本を守ってきれいな構造を保ち、その上でちょっとしたCSSを追加するだけで実現可能だ。 たとえ実際に印刷するニーズがなかったとしても、このような構造にすることでアクセシビリティを飛躍的に高めることができる。

それはスクリーン以外に対してということではなく、スクリーンにおいてもだ。 マイナーなウェブブラウザやミニマルなウェブブラウザにおいても、HTMLが完全なドキュメントであり、ブロック要素がブロックとして並んで表示されたときに支障がないようになっていれば困ることはない。

ひとつ注意点として、スクリーン向けのCSSをscreenメディアクエリ内に入れるのは良いことだが、グローバルにdisplay: none;を定義して、メディアクエリ内でブロックを表示させるようにすべきではない。 なぜならば、メディアクエリを読み込まないスクリーン環境で表示されなくなってしまうからだ。

重要なのは、あなたが日常的に使うスクリーン(特にメジャーでモダンなウェブブラウザ)がすべてではないということを正しく意識することだ。 HTMLやCSSは、決して一部のウェブブラウザのための修飾ではなく、オープンなデータフォーマットなのだから。