📑

腑分けして理解したいCSS組版 ページレイアウト

2024/12/13に公開

CSS組版アドベントカレンダー2024、13日目の記事です。

https://adventar.org/calendars/10448


前回までの粗筋

巻物(スクロール)メディアである通常のWebページに対し、冊子本(コデックス)に対応させる;ページネーションに対応させるCSSを適用するというのがCSS組版の基本です。

ページレイアウトとCSS組版

ページネーションはページあってのもの。そのページ上にどんな情報を、どのように載せるのか、これがページレイアウトということになります。

Webブラウザで「印刷」を選択し印刷操作を行うとき、プリンタ側の設定で印刷するページサイズを指定できるはずです。

「プリンタで設定できるものを何故CSSで指定しようとするのか?」

「Webページを印刷する」ことと「組版する」ことの第一の違いがここにあります。スクリーンではディスプレイやタブレット、スマートフォンなど様々なビューポートでコンテンツが表示され、どのサイズのビューポートでもコンテンツを最適に表示できる工夫を「レスポンシブデザイン」としています。一方の組版ではページというビューポートに固定されています。同じサイズの別のビューポートに、コンテンツを分けて並べて繋っているようにみせるのです。
(これ導入に書いておいた方がよかった気がする。)

CSS Paged Media Module Level 3 - @pageルール

https://drafts.csswg.org/css-page/#at-page-rule

ページレイアウトのためのCSSは@pageルールで記述します。

ページのサイズ size

ページサイズを明示するsizeを基本とします。

@page {
  size: 105mm 148mm; /*幅 × 高さ*/
}

上のCSSのように指定した場合、「幅105mm、高さ148mm」をページの基準サイズとします。
size: 5cm;とした場合は「幅5cm、高さ5cm」となります。

「ページのサイズって1つにしかできないの?」

いいえ。@pageは同じ文書内に幾つも指定可能です。違うサイズのページレイアウトを用意することも可能です。ただし、基本的にはCSSなので、後述する特別な書き方をしない限り指定内容は上書きされていってしまいます。

「B5しか使わないんだけれど、幅とか毎回直接指定しないといけないの?」

いいえ。*<page-size>*の値も可となっており、定義済みのキーワードを指定することで自動的にその判型になります。

指定値 説明
A5 ISOのA5。幅148mm高さ210mm
A4 ISOのA4。幅210mm高さ297mm
A3 ISOのA4。幅297mm高さ420mm
B5 ISOのB5。幅176mm高さ250mm
B4 ISOのB4。幅250mm高さ353mm
JIS-B5 JISのB5。幅182mm高さ257mm|
JIS-B4 JISのB4。幅257mm高さ364mm|
letter North American letter。幅8.5in高さ11in
legal North American legal。幅8.5in高さ14in
ledger North American ledger。 幅11in高さ17in

ということで、しれっと日本独自規格で有名なJIS B5とJIS B4がsize: JIS-B5のようにするだけで指定可能です。

size: JIS-B5って縦長じゃないと使えないの?」

いいえ。*<page-size>*は追加でportrait(縦長。肖像画が由来)またはlandscape(横長。風景画が由来)を指定すれば幅と高さの設定は逆になります。

ページマージン指定

ページのサイズが決まったら本文領域を決めます。項の題名が『ページマージン指定』となっていますが、この2つは表裏の関係にあります。余白が決まる→残りの領域が本文領域(コンテンツを流し込む領域)であり、本文領域が決まる→余白が決まる、ということです。

ページマージンの物理的必要性

ページの端ギリギリに本文領域が置かれることは通常ありません。デザイン文脈に於いての余白の重要性は置いておいて、物理的存在として次の要請があります。

  • ページを物理固定する指の置き場
  • 補助的な情報を表示可能な領域(主にナビゲーション)
  • 印刷、裁断に於ける安全マージン(余裕)

そして、冊子本の場合には加えて綴じによる差異が生じ得ます。

ページ進行方向、行進行方向、文字進行方向

ページネーションが機能するためには文書がどの方向に進むのかが分かっていなければなりません。というのも、とくに冊子本のように綴じがあると、コンテンツの配置位置によって物理的な見辛さが発生するからです。綴じ側の端(ノド)は開き辛くなります。そのことに配慮すると、左右どちらに配置されるページかで余白の取り方を変えることになります。綴じる辺を軸とした表ページ(recto)、裏ページ(verso)の誕生です。

- ページ進行方向 行(ブロック)進行方向 文字(インライン)進行方向 writing-mode
日本語横組 Right to Left Top to Down Right to Left horizontal-tb
日本語縦組 Left to Right Left to Right Top to Down vertical-rl

では、左右ページを異なるマージンにするためにはどうするのか。答えは疑似クラスです。でもその前にページマージンの指定方法の話に戻ります。

ページマージンの指定(全方向マージン指定バージョン)

@page {
    size: 105mm 148mm;
    margin-top: calc(12pt * 4);
    margin-bottom: calc(12pt * 3);
    margin-left: calc(12pt * 4);
    margin-right: calc(12pt * 4);
}

sizeのみを指定して組版したら「何か余白も適当に決まったっぽいのでOK!」という人はそんなにいないと思います。ページマージンは初期値autoによって処理系が適当に処理しますが、コンテンツを表示可能な領域を定めるというのは組版に於ける超重要事項なので、締切に余裕があるときにじっくり考えましょう[1]

ページマージンの指定(本文領域+2辺指定バージョン)

「marginの計算をしないと本文領域は決定できないの?」

いいえ。@pageにはwidthheightによって本文領域のサイズを直接指定可能です[2]

/* 横組想定のコメント */
:root {
--main-font-size: 8.5pt;
--main-line-height: calc(var(--main-font-size) * 1.4);
}

@page {
size: 105mm 148mm;
width: calc(var(--main-font-size * 38)); /*38字*/
height: calc(var(--main-line-height) * 78);/*ちょっと適当。行進行方向のサイズには実際にはハーフレーディングも考慮する必要があるので*/
margin-top: calc(var(--main-font-size) * 4);/*同上*/
margin-left: calc(var(--main-font-size) * 4);
}

先に述べたように、実際には本文の幅、高さを決めても各ページマージンは一意に定まりません。autoの場合、Webページ表示での常のように同じ長さに分けられますが、上下、左右の一辺ずつを決定すると、よりらしいレイアウトが実現可能です。

日本語組版では、本文領域の幅をメインの文字サイズの整数倍で設定すると利点があります。文字の幅が基本的に同じになるため、調整せずとも揃え易いという利点です[3]

widthheight + margin-(2方向) V.S. margin-*(全方向)

『デザインの守破離』(小林功二 編著,株式膾炙エムディーエヌコーポレーション)では、松田行正氏が書籍と雑誌の本文レイアウトの設計について言及しています。簡単には、書籍では文字サイズを基準として設計するが、それぞれのページのタイプグラフィ自由度の高い雑誌のような文書では全体のマージンを文字より優先するというものです。これはCSS組版の文脈でも同様に機能する話と感じました。

ページの疑似クラス(物理) :left :right

物理的に左のページのためのページレイアウトを:left・物理的に右のページのためのページレイアウトを:rightによって指定可能です。つまり、左右のページでそれぞれの横のマージン幅を変えられます。

:root {
--fore-edge: 36pt;
--back-margin: 48pt;
}

@page {
size: 105mm 148mm;
margin-top: 24pt;
margin-bottom: 36pt;
}

@page :left {
margin-left: var(--fore-edge);
margin-right: var(--back-margin);
}

@page :right {
margin-left: var(--back-margin);
margin-right: var(--fore-edge);
}

ページの疑似クラス(論理)

logical(論理)プロパティとして:recto:versoがあります[4]。所謂奇数ページ・偶数ページ相当ですね。綴じ方向をを軸にしたページの表・裏でもあります。つまり

:recto
: 日本語縦組(writing-mode="vertical-rl")の左ページ
: 日本語横組(writing-mode="horizontal-lr")の右ページ

:verso
: 日本語縦組(lang="ja" writing-mode="vertical-rl")の右ページ
: 日本語横組(lang="ja" writing-mode="horizontal-lr")の左ページ

最初のページ:first、調整用のアキページ:blank

最初のページだけ特別扱い(マージン無しでイラストを表示するとか)したい。:firstというものがあります。

@page {
...
}

@page :first {
margin: 0pt;
}

アキページを余白的にどうこうするのはあまりありませんが、余ったページを調整するときに使われるページレイアウトも:blankでできます。

:nth()の罠

https://www.w3.org/TR/css-gcpm-3/#document-page-selectors

:nth()という疑似クラスもあります。「nページ目を指定できるってこと!?」と狂喜乱舞しそうになっていたら、ちょっと待ってください。

確かに基本はそうなんです。
が、ページ数って基本的には「組版されるまで確定しない内容」なんですね。なので「4ページのページレイアウトだけ○○したい!」と思っても、4ページのコンテンツがそのページレイアウトに沿った内容であるかは結構調整が必要になります。:nth()は変数nを使った指定も可能ですが……。

@page :nth(2n+1) {...}/* 奇数ページごと。... :rectoでよくない?*/

まあ、実は使い所が難しいとだけ覚えてください。

名前付きページ

@page:firstやら:leftやらといった登場位置によるセレクタ分けの他に、名前を付けられるのです! というか:firstとか、素の@pageにしか使えなかったら本当に最初の1ページにしか使えないし。

@page {
  size: 105mm 148mm;
  ...
}
/*名前付きページ frontmatter*/
@page frontmatter :first {
  margin:0pt;
}

@page frontmatter :left {
    @bottom-left {
    ...
    }
}
@page frontmatter :right {
    @bottom-right {
    ...
    }
}
/* 名前付きページ mainmatter */

/*名前付きページ frontmatter*/
@page frontmatter :first {
  margin:0pt;
  background-image: url(...);
}

@page frontmatter :left {
    @bottom-left {
    ...
    }
}
@page frontmatter :right {
    @bottom-right {
    ...
    }
}

frontmatterの1ページ目ではページマージンが無いだけですが、mainmatterの1ページ目ではページ背景が設定されています。

指定したはいいが、どうやって適用するのか? これは定義した名前付きページをpageプロパティで指定することで適用されるのです。

body > header {
page: frontmatter;/* body>header のコンテンツに対し、frontmatterの:first,:rightまたは:left、:leftまたは:right...と使われる */
}

body > main >section {
page: mainmatter;/* body>main>section のコンテンツに対し、mainmatterの:first,:rightまたは:left、:leftまたは:right...と使われる */
...
  counter-increment: chap 1;/*(おまけ)*/
  counter-reset: sect 1;/*(おまけ)*/
}

発展編 トンボ

所謂トンボに代表される、物理的な印刷での裁断工程を考慮した処理のためのプロパティもPaged Mediaの仕様にあります。

商業的な印刷機では、A4やB5の紙を差し込んで印刷するわけではなく、もっと大きな紙に大きな機械で同時に複数のページを印刷し、裁断して予定のページサイズにするという工程があります。トンボは、裁断箇所の目印となります。
また、ハードウェア、物理的な世界では紙は収縮しますし、刃には厚みがあります。必然、裁断という工程は物理的なズレが生じる可能性があります。

これらに対応することがページメディア仕様に要求される事柄の1つです。

https://www.w3.org/TR/css-page-3/#marks

https://www.w3.org/TR/css-page-3/#bleed

  • marks 裁断位置を示すマークについてのプロパティ
  • bleed 塗り足しまたはドブと呼ばれる、物理的な裁断の揺れを吸収する余裕を持たせる領域の長さのプロパティ

bleedの初期値automarksに指定したマークの種類によって調整されます。

脚注
  1. 本アドカレの記事は常に締切に追われていますが ↩︎

  2. 猶、仕様ではmin-widthmax-widthといったトピックにも言及があり、こちらは少々ややこしい ↩︎

  3. 横組の実用書では和欧混合文になることも多いので効果は文書によりけりです ↩︎

  4. https://drafts.csswg.org/css-logical/#page ↩︎

Discussion