印刷用CSSを頑張って書いてみる

# はじめに 

帳票印刷用にHTMLを生成しなければならなくなったのですが、意外と苦労したので記録として残します。

# CSSの構成

自分以外の人にも使ってもらう予定なので、普通にブラウザで表示したときにも綺麗に見せる必要があります。

そこで、CSSを次のような構成にしました。

<dl>
  <dt>screen.css</dt>
  <dd>スクリーン表示用変数、印刷メニュー用のスタイルを指定する</dd>
  <dt>print.css</dt>
  <dd>印刷用変数の指定と、印刷メニュー用を非表示にする</dd>
  <dt>common.css</dt>
  <dd>共通の記述を書く</dd>
</dl>

## screen.css

FHDディスプレイでの横2ウィンドウ表示を想定して、ブレークポイント幅を `(1920px ÷ 2) - 10px = 950px` とします。
続いて基準となる基本単位(変数unit)を `ブレークポイント幅の90％ ÷ 1000` に指定します。
この単位を基準にして後ほど `common.css` で仮想用紙として使うHTML要素のサイズとフォントサイズを算出します。

ブレークポイントを下回った場合は、ビューポート幅の90％を基本単位の算出に利用しています。

残りの部分は、ほぼほぼ見た目のための記述です。(などと)

```css:screen.css
@charset "utf-8";
@import url('./common.css');

/* ============================================================ */
/*  Copyright (c) 2024 CIB-MC                                   */
/*  Released under the MIT license                              */
/*  https://opensource.org/licenses/mit-license.php             */
/* ============================================================ */

:root {
    --unit: calc((950px * 0.9) / 1000); /* (ブレークポイント幅90%) ÷ 1000 */
}

body {
    background-color: #aaa;
}

main .page {
    margin: 0 0 2em 0;
    box-shadow: 0.4em 0.4em 0.25em rgba(0,0,0,0.4);
}

.header-menu {
    width:100%;
    background-color: lightskyblue;
    margin-bottom: 2em;
}

.header-menu .inner {
    margin: 0 auto;
    min-width: 20rem;
    font-size: 1.2rem;
    padding: 1rem;
    text-align: center;
}

.header-menu button {
    font-size: inherit;
}

@media screen and (max-width: 950px) {
    :root {
        --unit: calc(90vw / 1000); /* (ビューポート幅90％) ÷ 1000 */
    }
}
```

## print.css

1単位を `210mm(A4横幅) ÷ 1000` としています。 
~~ぼんやりして基準を210cmにして大変なことになったのは秘密です。~~

用紙に想定するA4縦を指定しておきましょう。

印刷メニュー要素につける `no-print` クラスを非表示にしましょう。

```css:print.css
@charset "utf-8";
@import url('./common.css');

/* ============================================================ */
/*  Copyright (c) 2024 CIB-MC                                   */
/*  Released under the MIT license                              */
/*  https://opensource.org/licenses/mit-license.php             */
/* ============================================================ */

:root {
    --unit: calc(210mm / 1000); /* A4横幅 ÷ 1000 */
}

@page {
	margin: 0;
	size: A4 portrait;
}

.no-print {
    display: none;
}
```

## common.css

様々なデバイスから参照される可能性を考慮してWebフォント(Google Fonts)を導入して指定しています。

お好みに応じて別のWebフォントを利用したり、閲覧される環境に特定のフォントがインストールされていることが保証されている場合はそれを指定してもいいと思います。

仮想用紙の高さを `基準単位 × 1000 × 2の平方根` とします。
※A4の縦横比は `√2:1` であるため。
※横幅も変数に入れておいてもよかったかもしれません。(記事を書いていて気づいた)

フォントサイズや幅を指定する際は基本単位を基準にして指定しましょう。
もしくは `html` でフォントサイズを基本単位から計算して指定してあるので `rem` を使って指定しても構いません。

```css:common.css
@charset "utf-8";
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100..900&display=swap');

/* ============================================================ */
/*  Copyright (c) 2024 CIB-MC                                   */
/*  Released under the MIT license                              */
/*  https://opensource.org/licenses/mit-license.php             */
/* ============================================================ */

html,body{
    height: auto;
    margin: 0;
}

html {
    font-size: calc(var(--unit) * 20);
    font-family: "Noto Sans JP", sans-serif;
}

main {
    margin: 0 auto;
    width: calc(var(--unit) * 1000);
}

main .page {
    height: calc(var(--unit) * 1000 * sqrt(2));
    padding: calc(var(--unit) * 40);
    box-sizing: border-box;
    overflow: hidden;
    background-color: #fff;
}

/* ここから下はお好みで */

.huge-text-1 {
    font-size: 1.8rem;
    line-height: 1.1em;
}

.huge-text-2 {
    font-size: 2.5rem;
    line-height: 1.1em;
}

p {
    margin-top: 0;
}
```

# 実際の表示

次のHTMLを用意して、表示を確認してみましょう。
最終的に帳票印刷での利用を想定しているので、ページを分ける際は `page` クラスのついた要素を増やしてください。

記事コンテンツなど、ページ区切りを指定したくない(個別に指定できない)場合は `page` クラスから高さ指定とオーバーフロー指定を外すと幸せになれるかもしれません。(未検証)

```html:index.html
<!doctype html>
<html>
<!--
============================================================
 Copyright (c) 2024 CIB-MC
 Released under the MIT license
 https://opensource.org/licenses/mit-license.php
============================================================
-->
    <head>
        <meta charset="UTF-8">
        <title>Print CSS Sample Page</title>
        <link href="./screen.css" media="screen" rel="stylesheet">
        <link href="./print.css"  media="print" rel="stylesheet">
    </head>
    <body>
        <header class="header-menu no-print">
        <div class="inner">
            こちらは印刷用ページです。 <button type="button" onclick="window.print();">印刷</button>
        </div>
    </header>
    <main>
        <div class="page">
            <p>テストテキストです。テストテキストです。テストテキストです。テストテキストです。テストテキストです。テストテキストです。テストテキストです。</p>
            <p class="huge-text-1">テストテキストです。テストテキストです。テストテキストです。テストテキストです。テストテキストです。テストテキストです。テストテキストです。</p>
            <p class="huge-text-2">テストテキストです。テストテキストです。テストテキストです。テストテキストです。テストテキストです。テストテキストです。テストテキストです。</p>
            
        </div>
    </main>
    </body>
</html>
```

## ブレークポイント以上の表示

![fig_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2066798/401e1dc9-3a2a-b3bf-411a-770f4135e9f2.png)

## ブレークポイント以下の表示

![fig_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2066798/03176715-f105-fade-fd00-1f1a10ca1bb3.png)

## 印刷プレビューの表示

![fig_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2066798/6784e508-0c81-438d-4d7b-a468d7f8d967.png)

# 最後にオチ

レスポンシブにはできませんが、スクリーン表示用のスタイルでも `mm` 単位でサイズ指定すれば簡単に表示を揃えられます。