Vivliostyle Viewer で CSS 組版ちょっと入門

村上 真雄 @MurakamiShinyu

Vivliostyle は、CSS 組版で本を作るためのツールとして、少しずつ知られるようになってきたかと思います。そして、最近の更新では、目次ナビゲーション機能、Web Publications 対応など、Web/電子出版ビューアとしても、使い勝手のよいものを目指しています。この「Vivliostyle Viewer で CSS 組版ちょっと入門」では、Vivliostyle Viewer でできることを中心にした CSS 組版のちょっとだけ入門を書いてみます。

Vivliostyle Viewer の紹介

Vivliostyle Viewerhttps://vivliostyle.github.io/vivliostyle.js/viewer/vivliostyle-viewer.html は、ブラウザ上で動作する CSS 組版エンジン vivliostyle.js とビューア UI vivliostyle-ui でできています。

何をするもの?

Vivliostyle Viewer は次のように使われることを想定してます:

設置・インストールについて

設置・インストールと使い方について、Vivliostyle Viewer ユーザーガイドhttps://vivliostyle.github.io/vivliostyle.js/docs/ja/もご覧ください。

Vivliostyle Viewer の最初の画面

Vivliostyle Viewer の URL をパラメータなしで開くと、文書 URL の入力欄(“Input a document URL”)と使い方の説明が表示されます。(説明書きは今のところ英語だけですが、Vivliostyle Viewer ユーザーガイド(日本語)https://vivliostyle.github.io/vivliostyle.js/docs/ja/に日本語訳があります。)

文書 URL の入力欄に表示対象の文書の URL を入れて Enter キーを押すと、その文書をロードして組版結果を表示します。これは Vivliostyle Viewer のURLに、フラグメントパラメータ#b=<文書のURL>で表示対象の文書を指定したのと同じことになります。

なお、URL を入力する代わりに、HTML コードを入れることもできて、ちょっと Vivliostyle の組版を試してみるのに使えます。これで例えば<p>Hello, world!</p>から CSS 組版をはじめられます。

Vivliostyle Viewer スタート画面の文書 URL 入力欄に Hello, world! と入力したところ
Vivliostyle Viewer スタート画面の文書 URL 入力欄に<p>Hello, world!</p>と入力したところ

設定パネルからできること

Vivliostyle Viewer の画面右上の設定ボタン Settings (S) をクリック(または、キーボードの S キー)で、設定パネルが表示されます。ここで設定を変更して Apply ボタンを押すと設定内容が適用されます。(Apply で通常はパネルが閉じますが、設定ボタン 2 度押しでパネルを開くと、適用してもパネルが開いたままにできます)。

Vivliostyle Viewer の設定パネル
Vivliostyle Viewer の設定パネル

全ページをレンダリング(Render All Pages)On/Off設定

この設定は、全ページのレンダリング(ブラウザのメモリ上でページを生成する組版処理をして表示や印刷ができる状態にする)を常に行うかどうかを指定します。Vivliostyle Viewer を使う目的によって、この設定が必要です:

全ページの印刷/PDF 出力を行う場合や、CSS のページカウンタ(counter(page), counter(pages))を正しく表示するには、全ページをレンダリングするモード(Render All Pages: On)にする必要があります。

閲覧向き(Render All Pages: Off)のモードでは、多数の HTML ファイルで構成される大規模な出版物(EPUB や Web Publications など)を、途中から閲覧するような場合にその部分だけの組版・ページ生成処理をするので、処理時間を待たされることなく閲覧できます。ページ番号のカウントは、実際に組版した結果のページ数ではなく、各 HTML ファイルの大きさと、HTML ファイル内での各要素の位置から計算された、擬似的なページ番号になります。

ユーザースタイル設定(User Style Preferences)

設定パネルの▶ User Style Preferencesを開くと次のユーザースタイル設定項目があります:

設定される CSS コードの確認と追加・編集(CSS Details)

▶ CSS Details を開くと、ユーザースタイル設定の内容の CSS コードを確認することができます。また、ここでユーザーが CSS コードを直接書くこともできます。その場合は自動生成されたコメント/*<viewer>*//*</viewer>*/で囲まれてた部分はそのままにして、その前か後に追加するようにしてください。

設定内容は URL パラメータに反映

設定パネルで設定した内容は、Vivliostyle Viewer の URL パラメータに反映されるので、この設定付きの URL をブックマークしたり公開することもできます。 例えば、Vivliostyle Viewer ユーザーガイド にある Web 上に公開されている文書に、設定パネルからユーザースタイルの設定を加えた例: 『Cascading Style Sheets Level 2 Revision 2 (CSS 2.2) Specification』

Vivliostyle CSS 組版ちょっと入門

ここでは、Vivliostyle Viewer で閲覧できて、印刷・PDF 出力できるような「本」を作るための、ちょっとしたポイントを解説します。

章ごとの HTML ファイルをまとめて本の形にする方法

これまで CSS 組版で本を作る場合、原稿は章ごとに分けて書いていても、最後にひとつの大きな HTML ファイルにまとめたものを CSS 組版のソースにする方法がよく行われてました。

しかし、Vivliostyle では複数の HTML ファイルのまま、まとめて組版して本の形にする方法が便利でおすすめです。

複数の HTML ファイルをまとめる形式はいくつかあります。

表紙から目次までをindex.html

最初の HTML ファイルの名前をindex.htmlとして、これに表紙(タイトルページ)から目次までを記述する例を説明します。

index.htmlの例
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>簡単な本</title>
</head>
<body>
  <header>
    <h1>簡単な本</h1>
  </header>
  <nav id="toc" role="doc-toc">
    <h2>目次</h2>
    <ol>
      <li><a href="chapter1.html">最初の章</a></li>
      <li><a href="chapter2.html">2番目の章</a></li>
      <li><a href="chapter3.html">最後の章</a></li>
    </ol>
  </nav>
</body>
</html>
各章の HTML の例(chapter1.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>最初の章</title>
</head>
<body>
  <h1>最初の章</h1>
  <p>ほげ。</p>
</body>
</html>

このようにindex.htmlファイルと、各章の HTML ファイルを用意して、index.html の URL を Vivliostyle Viewer の#b=パラメータに指定して開くと、組版結果が表示されます。最初のページがタイトルと目次で、目次の項目をクリックするか、→または↓でページを進めると、各章のページへと移動します。目次パネル(Viewer 画面左上のボタンで表示)からのナビゲーションも有効になります。

改ページの指定 break-before: page | left | right | recto | verso

この「簡単な本」の例を、より「本」らしくするには、最初のページはタイトルが書かれた表紙ページ、ページをめくると目次ページ、とするのがよいでしょう。それには、まず、目次の要素の前で改ページするように CSS で指定します。CSS Fragmentationhttps://drafts.csswg.org/css-break/ 仕様で定義されているbreak-beforeプロパティを使います。

nav {
  break-before: page; /* この要素の前で改ページ */
}

break-beforeプロパティの値pageの代わりに、leftまたはrightを指定することもできて、改ページしたあとのページが見開きの左側または右側のページになるように自動的に空白ページを入れて改ページさせることができます。また、rightleftの代わりにrectoversoという値を指定することもできます。これは、「表側」・「裏側」という意味で、ページ進行方向が左から右ならrecto=rightverso=left、ページ進行方向が右から左ならその逆です。(つまり、表紙と同じ側がrectoでその裏側がverso、奇数ページ番号がrectoで偶数ページ番号がverso。)

表紙のページスタイル @page :first {...}

CSS Paged Mediahttps://drafts.csswg.org/css-page-3/ 仕様では、@pageルールで、ページサイズや余白などを指定します。

@page {
  size: A5;
  margin: 15mm;  /* ページの上下左右の余白を15mmずつに */
  @top-center {
    content: "簡単な本";    /* ページヘッダーにタイトル */
  }
  @bottom-center {
    content: counter(page); /* ページフッターにページ番号 */
  }
}

そして、@page :first {...}という構文で、文書の最初のページだけのスタイルを指定できるので、表紙のページを作るのに役に立ちます。

@page :first {
  background-color: gold; /* ページ全体に背景色 */
  margin: 0;              /* ページ余白無し */
  @top-center {
    content: none;        /* ページヘッダー無し */
  }
  @bottom-center {
    content: none;        /* ページフッター無し */
  }
}

目次の作り方

HTML で目次を作るおすすめののマークアップは次のようなものです:

  <nav id="toc" role="doc-toc">
    <h2>目次</h2>
    <ol>
      <li><a href="chapter1.html">最初の章</a>
        <ol>
          <li><a href="chapter1.html#section1">はじめのセクション</a></li>
          <li><a href="chapter1.html#section2">ふたつめのセクション</a></li>
          ...
        </ol>
      </li>
      <li><a href="chapter2.html">2番目の章</a>
        ...
      </li>
      <li><a href="chapter3.html">最後の章</a>
        ...
      </li>
    </ol>
  </nav>

「目次」を表す role 属性の値 "doc-toc" は、Digital Publishing WAI-ARIAhttps://www.w3.org/TR/dpub-aria-1.0/ という仕様で定義されてます。Vivliostyle は、この属性のある要素(通常は<nav>)を目次として認識して、リンクされている HTML をまとめて一冊の本のように扱い、Viewer の目次パネルのナビゲーションも有効にします。

Vivliostyle Viewer での目次パネル

Vivliostyle Viewer の目次パネル
Vivliostyle Viewer の目次パネル

目次パネルでは、HTML の目次の項目のリスト(<ol>または<ul>要素)から、↓↑←→キーで操作できるツリー状のリストになります。章→セクション→サブセクションのような多階層の目次はリスト要素をネストさせて作ります。目次パネルでは最初トップレベルの項目のみ表示されて、「▸」をクリックして下位の項目が出るようになってます。

ページ番号参照 target-counter()

HTML の目次はリンクになってます。PDF でもリンクが有効です。でも紙の本にした場合はページ番号が必要でしょう。

CSS Generated Contenthttps://drafts.csswg.org/css-content/ 仕様で定義されているtarget-counter()関数を、リンク要素<a>::after擬似要素のcontentプロパティの値に使うことで、各目次項目のリンク先のページ番号を入れられます。

nav li a::after {
  content: target-counter(attr(href), page);
}

ページ番号を右寄せにして目次項目との間を点線で埋めるのは、次のように CSS Flexbox のinline-flexを使ってできます:

nav li a {
  display: inline-flex;
  width: 100%;
  text-decoration: none;
  color: currentColor;
  align-items: baseline;
}
nav li a::before {
  margin-left: 0.5em;
  margin-right: 0.5em;
  border-bottom: 1px dotted;
  content: "";
  order: 1;
  flex: auto;
}
nav li a::after {
  text-align: right;
  content: target-counter(attr(href), page);	
  align-self: flex-end;
  flex: none;
  order: 2;
}

目次ページ
目次ページ

注意:ページ番号が正しく表示されるには、全ページをレンダリング(Render All Pages)の設定が On である必要があります。

各章を左ページあるいは右ページからに

各章を HTML ファイルひとつずつで作る場合、各 HTML は改ページした新しいページから開始するので、明示的の改ページの指定break-before: pageは不要ですが、各章を必ず左右ページ(あるいは奇数・偶数ページ)のどちらかから開始するといった場合には、次のように<body>要素に指定します:

body {
  break-before: recto; /* 奇数ページから開始 */
}

ページヘッダー/フッター(ページマージンボックス)

@pageルールで次のように書くと、文字列(タイトルなど)やページ番号や画像をページヘッダー/フッターに出力することができます:

@page {
  @top-center {
    content: "サンプル文書";  /* 固定の文字列を出力 */
  }
  @bottom-center {
    content: counter(page) " / " counter(pages); /* 「ページ番号 / 総ページ数」を出力 */
  }
  @top-right-corner {
    content: url(images/logo.png);  /* 画像を出力 */
  }
}

ページヘッダー/フッターを指定する@top-center@bottom-centerなど(ページマージンボックスという)は CSS Paged Media 仕様で次の 16 個が定義されています。

@top-left-corner @top-left @top-center @top-right @top-right-corner
@left-top @right-top
@left-middle @right-middle
@left-bottom @right-bottom
@bottom-left-corner @bottom-left @bottom-center @bottom-right @bottom-right-corner

章タイトルなどをページヘッダー/フッターに env(pub-title)env(doc-title)

Vivliostyle では、env(pub-title)あるいはenv(doc-title)という特別な変数を使うことができて、これで本のタイトルや、章のタイトルを、ページヘッダー/フッターに出力することができます。

本を作るのに章ごとの HTML ファイルにしている場合、env(pub-title)は本のタイトル、env(doc-title)は章のタイトルということになります。

左右ページのレイアウト @page :left@page :right

次は、本の見開きページの左側と右側のページヘッダーにそれぞれ本のタイトルと章のタイトルを出力するという例です:

@page :left {     /* 左側ページ */
  @top-left {
    content: env(pub-title);  /* 本のタイトル */
  }
}
@page :right {    /* 右側ページ */
  @top-right {
    content: env(doc-title);  /* 章のタイトル */
  }
}

ページヘッダー/フッターへのフォントの指定

CSS Paged Media 仕様で、継承プロパティの値は、ページマージンボックス(@top-left {...}など)はページコンテキスト(@page {...})から継承して、ページコンテキストはルート要素から継承するとされています。 ただし、Vivliostyle は現在のところ、ルート要素からページコンテキストへのプロパティ値の継承は未サポートです。したがって、ページヘッダー/フッターに共通のフォントの指定をしたい場合は、ルート要素とは別に@page {...}にそのフォントの指定をする必要があります。

@page {
  font-family: "IPAexGothic", sans-serif;
  font-size: 0.75rem;
}

このように@page {...}にフォントの指定をすると、ページマージンボックス(@top-left {...}など)に継承されるので、個別のページマージンボックスに指定しなくてもすみます。そして、ページの本体のほうの基本のフォントは、@page {...}ではなくて、ルート要素(html {...}あるいは:root {...})で指定します。

トンボをつけるには

印刷物を作るとき、ページの仕上がりサイズに断裁するための位置合わせのために、ページの四隅などに付ける目印のことをトンボといいます。これを出力するための CSS プロパティが CSS Paged Media 仕様で定義されていて、Vivliostyle はこれを実装しています。

トンボを出力 marks: crop cross

@page {
  size: A5;
  marks: crop cross;
  bleed: 3mm;
}

marksプロパティの値cropは四隅のトンボ、crossは上下・左右の中央の位置を示すトンボです。通常は両方指定します。

塗り足し bleed: 3mm

bleedプロパティは、塗り足し領域(bleed)の幅を指定します。ページの端まで色を塗るとき、ページの仕上がりサイズぴったりのところまでしか色が塗られていないと、そこで断裁したときのずれによって塗られていない白い部分が残ってしまうため、ページの外側にはみ出して色を塗る塗り足し領域が必要です。このプロパティの仕様でデフォルトは 6pt(約 2.1mm)ですが、日本の印刷業界では 3mm とするのが標準的なのでbleed: 3mmを指定します。

ページの背景色を塗り足し領域に広げる例

本の表紙のページ全体とタイトルのまわりに背景色をつけた例:

@page :first {
  background-color: gold; /* ページ全体に背景色 */
  marks: crop cross;      /* トンボを付ける */
  bleed: 3mm;             /* 塗り足し領域 */
  margin: -3mm;           /* ページ領域を塗り足し領域まで広げる */
}
header {
  background: rebeccapurple;
  padding: 5vh 5vw;
}
header h1 {
  font-size: 4rem;
  text-align: center;
  color: white;
}
<body>
  <header>
    <h1>簡単な本</h1>
  </header>
  ...

トンボと塗り足しありで出力した簡単な本の表紙
トンボと塗り足しありで出力した簡単な本の表紙

この例では、@pageルールにmargin: -3mmという指定をすることでページ領域を塗り足し領域まで広げて、ページ内に配置する要素(この例では紫色の背景色をつけた本のタイトル部分のブロック)が塗り足し領域から配置されるようにしています。

通常のページ余白(margin: 15mmなど)があるページの場合で、写真をページの隅に配置するような場合には、その要素にマイナスのマージン(ページ余白と塗り足し領域の分)を指定することで、写真の端を塗り足し領域まで広げるようにするとよいでしょう。

@page {
  marks: crop cross;      /* トンボを付ける */
  bleed: 3mm;             /* 塗り足し領域 */
  margin: 15mm;           /* ページ余白 */
}
img.photo {
  float: right;
  margin-right: -18mm;    /* 画像右端を塗り足し領域に */
}

写真を塗り足し領域から配置してるページ
写真を塗り足し領域から配置してるページ

ちょっと入門はここまで

ちょっと入門の次は、次のようなトピックなど、

またの機会に。

チュートリアル「簡単な本」サンプルはGist https://gist.github.com/MurakamiShinyu/ に公開https://gist.github.com/MurakamiShinyu/4f0423fd3578a277c7d29f56a31912b7/しています。