CSSにまだ詳しくなかったり、ページデザインよりも本文の執筆に注力したい人のために、Vivliostyleでは簡単にデザインを適用できる
Vivliostyle Themeについて
Vivliostyle Themeは、Vivliostyleワークフロー上で簡単にページデザインを適用するための仕組みです。CSS組版を実現するVivliostyleは、ページデザインをCSSで実現できることが最大のメリットですが、逆説的に言うとCSSを知らないとデザインの変更ができないとも言えます。CSS自体は広く普及しており、CSSを学ぶ環境も十分に整えられてはいるものの、Vivliostyleを扱う人すべてがCSSに詳しいとは限りません。そのため、Vivliostyle Themeではいくつかの主要なユースケースに沿ったデザインのプリセットを
Vivliostyle公式では、文庫本用のテーマ@vivliostyle/)@vivliostyle/)
Vivliostyle Themeの使い方
それではVivliostyle Themeを実際に使っていきます。第1回で用意したVivliostyleサンプル
Vivliostyle Themeを使用する前に、すでに本文に適用されているスタイルシートを解除しておきます。複数のテーマやスタイルシートを適用させることも可能ですが、スタイルが競合することを避けるため、今回はVivliostyle Themeのみを使うようにします。以下のように、本文ファイルのフロントマターからlink:を削除します。
---
title: 植物一日一題
author: 牧野富太郎
lang: ja
---
この状態でプレビュー画面を表示すると、以下のスクリーンショットのように、ブラウザデフォルトのスタイルシートのみが適用された状態になるはずです。
この状態から、Vivliostyle Themeを使用します。Vivliostyle CLIでは、--theme-T)
$ vivliostyle preview shokubutsu_ichinichi.md --theme @vivliostyle/theme-bunko
すると、以下のようにテーマが適用された状態でプレビューされます。
この例ではテーマを@vivliostyle/のように名前で指定しましたが、ローカル環境やWeb上のテーマを直接指定することもできます。また、前述した通りVivliostyle ThemeはCSSファイルをテーマとして扱うため、CSSファイル自体を直接指定することもできます。
$ vivliostyle preview shokubutsu_ichinichi.md --theme ./css/styles.css $ vivliostyle preview shokubutsu_ichinichi.md --theme https://unpkg.com/markdown-splendor/css/splendor.css
このように、Vivliostyle Themeは全くCSSを書くことなくページのスタイルを変えることができます。もちろんこのままでも十分にVivliostyle Themeを活用できていますが、以降の章で紹介する簡単なCSSを用意することで、スタイルの内容をカスタマイズすることもできます。
テーマのカスタマイズ
公式が提供するVivliostyle Themeの大部分では、CSS変数を使ったテーマのカスタマイズをサポートしています。例えば、文章全体のフォントを変更したい場合は、--vs-font-familyというCSS変数が使用できます。テーマの指定オプションに加えて、以下のように--cssオプションで直接CSSを与えてみてください。
$ vivliostyle preview shokubutsu_ichinichi.md \
    --theme @vivliostyle/theme-bunko \
    --css ':root {--vs-font-family: YuGothic;}'
これで、文章全体のフォントが游ゴシック体に変化しているはずです。--vs-font-family以外にも、Vivliostyle Themeでは様々な値がカスタマイズ可能になっており、これらのCSS変数は--vsで始まる名前で用意されています。例として、以下のようなCSS変数が設定可能です。
--vs-font-size- 文章全体で基準となるフォントの大きさ
(CSSの font-sizeプロパティに相当) --vs-line-height- 文章全体で基準となる行の高さ。通常の
line-heightプロパティとは異なり、この値には単位のない<number>を指定する必要があることに注意してください --vs-columns- 段組の数や幅の大きさ
(CSSの columnsプロパティに相当) --vs-hanging-punctuation- 句読点のぶら下げに関する指定
(CSSの hanging-punctuationプロパティに相当) --vs-text-spacing- 約物の詰めや和欧文間のスペースに関する指定 (CSSの
text-spacingプロパティに相当) --vs-writing-mode- 縦書き・
横書きの指定 (CSSの writing-modeプロパティに相当) --vs-widows-orphans- 一つの段落が複数のページ・
段組にまたがるときに確保する最小の行数 (CSSの widowsプロパティ、orphansプロパティに相当) --vs-spacing-rlhp、ul、tableなどのブロック要素が確保するマージンの大きさ。<length>の値を指定します
これらのカスタマイズ可能な設定は、Baseテーマを介して定義されています。Baseテーマについては後ほど紹介します。
他にも、テーマによってはそのテーマ特有のカスタマイズ可能なオプションが用意されていることがあります。BunkoテーマのREADMEには、--vs-theme--num-of-lineや--vs-theme--num-of-characterなどの利用可能なCSS変数が紹介されており、このCSS変数の内容をカスタマイズすることで1ページあたりの行数と一行の文字数が設定できることがわかります。コマンドで指定するにはちょっと長いので、別のCSSファイルmy-style.を作成して、そこに上書きするCSS変数を書いていきます。
:root {
  --vs-font-family: YuGothic;
  --vs-page--size: JIS-B6;
  --vs-theme--num-of-line: 14;
  --vs-theme--num-of-character: 40;
}
以下のように作成したCSSファイルを--styleオプションで指定してください。
$ vivliostyle preview shokubutsu_ichinichi.md \
    --theme @vivliostyle/theme-bunko \
    --style ./my-style.css
このCSS変数の指定により、フォントが游ゴシック体に、ページの大きさがJIS-B6に、1ページあたりの行数が14、一行の文字数が40になります。
このように、Vivliostyle CLIの--cssオプションや--styleオプションは、既存のVivliostyle Themeに簡単なカスタマイズを加えるのに便利です。もし、より複雑なカスタマイズをしたり、カスタマイズしたスタイル自身をテーマとして再利用したい場合は、後述する手順で新しくテーマを作ることをおすすめします。
Note:Vivliostyle Themeを指定するとthemesという名前のディレクトリが作られていることにお気づきかもしれません。このファイルはVivliostyle CLIが自動でインストールしたテーマファイルを保存するディレクトリです。このディレクトリの中のファイルはVivliostyle CLIによって書き換えられる可能性があるため、このディレクトリの中のCSSファイルは直接編集せず、別の場所にCSSファイルを作成して編集するようにしてください。
柔軟なデザインを支えるBaseテーマ
Vivliostyle Themeを知るためには、実際にテーマがどのように作られているかを見るのが一番です。例えば、BunkoテーマのCSSファイルは以下のようになっています。
@import url(../theme-base/theme-all.css);
/**
 * Theme variables
 */
:root {
  --vs-theme--num-of-line: 15;
  --vs-theme--num-of-character: 39;
  --vs-theme--page-top-left-content: counter(page) ' ' env(doc-title);
  --vs-theme--page-top-right-content: counter(page);
  --vs-theme--subsection-text-indent: 3rem;
  --vs-theme--anchor-color-body: darkblue;
}
:root {
  --vs-border-width: 0.5px;
  --vs-font-family: '游明朝', 'YuMincho', serif;
  --vs-font-size-on-print: 83.33%;
  --vs-line-height: 2;
  --vs-spacing-rlh: 0;
  --vs-writing-mode: vertical-rl;
  .....
}
.....
上記のコードは実際のCSSの抜粋ではありますが、それでもBunkoテーマのためのCSSは全体で187行 (執筆時点) に収まっています。実際にBunkoテーマが実現していることに対して、この分量はとても少なく感じませんか?
この理由を知るためには、もう少しCSSについて踏み込んで見ていく必要があります。CSSの1行目に@import url(../という箇所がありますが、これは Baseテーマ@vivliostyle/)
Baseテーマ自体のCSSは、meta-properties.
CSS変数を介して設定する意義
Baseテーマが提供するCSS変数は、部分的に独自のカスケーディングのルールにしたがって定義されています。例えば、Baseテーマでは見出し要素 (h1〜h6) に対して heading というグループがあります。このグループに対して、以下のように一括でスタイルを適用したり、その中の特定の要素だけに別のスタイルを適用する、といったことができるようになっています。
:root {
  /* 見出しh1〜h5にフォントAを適用 */
  --vs--heading-font-family: A;
  /* h6にだけフォントBを適用 */
  --vs--h6-font-family: B;
}
ただ、CSSに詳しい人であれば、わざわざこのようなルールを作らなくても、以下のように:root以外のセレクターを用意して直接フォントを指定すれば良いと思うかもしれません。このようにしなかった理由はなぜでしょうか?
h1, h2, h3, h4, h5 {
  --vs-font-family: A;
}
h6 {
  --vs-font-family: B;
}
CSSでは、複数のスタイルが重複して設定された場合、セレクターの詳細度に応じて優先度を決めるというルールがあります。この特徴は、正しく管理されたCSSの範囲では柔軟に制御できる機能である一方、外部のCSSがそのスタイルを再利用するためには、元のCSSのスタイルを上書きするためにより高い詳細度を設定する必要があります。この制約は、再利用元のCSSの内容に依存することになり、結果として詳細度を上げるための無意味なセレクターや!importantの使用といったCSSのバッドプラクティスに繋がります。特に、Vivliostyle Themeのように一つのCSSファイルが数多くのテーマから参照される場合、注意深くセレクターを設定しなければいけません。実際に、CSS変数を使用していなかった以前のVivliostyle Themeでは、この問題が原因でBaseテーマのような再利用可能なCSSを作ることができませんでした。
Baseテーマは、このような詳細度に関する問題を避けつつも、独自のカスケーディングのルールを用意することで、文章を主体としたページのレイアウトを簡単にする取り組みです。もちろん、CSS変数の名前だけでセレクターを代替しようとするこの方法は、現実世界のWebサイトで求められるような複雑なセレクターの表現は難しいでしょう。しかし、Vivliostyleが対象とするような構造化されたコンテンツに対しては、CSSの再利用をより柔軟にする方法だと思いませんか?
CSSカウンターの使用
Baseテーマの導入でVivliostyle Themeがより使いやすくなった一例として、CSSカウンター の例について紹介します。CSSカウンターとは、ページ内の要素に対して決まったルールでカウントし、その要素の出現回数に応じて番号を増加・
CSSカウンターを使うためには、通常以下のようなCSSを用意します。
body {
  /* my-counterのカウンター値をリセット */
  counter-reset: my-counter;
}
h1::before {
  /* h1要素が出現するたびにカウンターの値を1つ増加させる */
  counter-increment: my-counter;
  /* h1要素のテキストにカウンターの値に応じて「第n章」というテキストを追加する */
  content: '第' counter(my-counter) '章';
}
ただ、このようにCSSカウンターを直接使用する方法には若干問題があります。単純にcounter-resetやcounter-incrementを設定することが面倒という点もありますが、それよりも問題なのはcounter-resetやcounter-incrementが他のCSSで上書きできてしまうという点です。例えば、上記のCSSとは別にbody { counter-reset: another-counter; }のようなCSSを後から読み込ませた場合、元のmy-counterのカウンターリセットは無効化されてしまいます。この仕様は、Vivliostyle Themeの再利用性を実現する上で問題です。
Baseテーマを利用するVivliostyle Themeでは、この問題を回避するための手段を提供しています。まず、見出し番号や図表の番号といったよく用いられるカウンターについては、標準で利用可能な状態にしています。試しに、以下のようなCSS変数を設定してみてください。
:root {
  --vs-section--marker-display: inline;
}
すると見出しの先頭に見出し番号が表示されます。--vs-section--marker-displayは見出し番号の表示に関する設定で、デフォルトのnoneからinlineに変更することで非表示の状態だった見出し番号を表示させるように指定しています。見出し番号を始めとしたカウンターがどのように利用できるかを紹介します。
見出し番号のカウンター
見出し、小見出しといった章に関するカウンターは section.
| カウンター名 | 説明 | 
|---|---|
vs-counter-sections | 
見出しを持つセクションのカウンター | 
vs-counter-sec-h1〜vs-counter-sec-h6 | 
h1〜h6を持つセクションのカウンター | 
このとき、見出し番号のカウンターはh1やh2といった見出しに対してインクリメントされるのではなく、見出しを持つセクションに対してインクリメントされることに注意が必要です。ここで言うh1〜h6を持つsection要素」
<section>
  <h1>1 大見出し</h1>
  <section>
    <h2>1.1 見出し</h2>
    <p>.....</p>
  </section>
  <section>
    <h2>1.2 見出し</h2>
    <p>.....</p>
    <section>
      <h3>1.2.1 小見出し</h3>
      <p>.....</p>
    </section>
  </section>
</section>
なお、第2回で紹介した通り、VFMが出力するHTMLは自動的に見出しごとにセクション分けされます。また、この仕様を利用して意図的に見出し番号を表示させないこともできます。VFMでは、行頭に#をつけて設定した見出しに対して同じ数の#を行末につけることでセクションを作らずに見出しを作成することができる ので、これにより見出し番号のカウンターをインクリメントせずに見出しを作ることができます。
また、デフォルトではすべての見出しに対して階層的な見出し番号を表示していますが、この動作を変えることもできます。以下に見出し番号を制御する例を紹介します。
h1、h2要素だけ見出し番号を表示
:root {
  --vs-section--h1-marker-display: inline;
  --vs-section--h2-marker-display: inline;
}
h1の見出し番号のスタイルを変更
:root {
  --vs-section--marker-display: inline;
  --vs-section--h1-marker-content: counter(vs-counter-sections, upper-roman);
}
セクション単位でリセットされていない通算の番号を表示
:root {
  --vs-section--marker-display: inline;
  --vs-section--h2-marker-content: counter(vs-counter-sec-h1) '.' counter(vs-counter-sec-h2);
  --vs-section--h3-marker-content: counter(vs-counter-sec-h1) '.' counter(vs-counter-sec-h2) '.' counter(vs-counter-sec-h3);
}
図表カウンター
図表や引用に関するカウンターは crossref.
| カウンター名 | 説明 | 
|---|---|
vs-counter-fig | 
図のカウンター | 
vs-counter-tbl | 
表のカウンター | 
vs-counter-cite | 
引用のカウンター | 
それぞれのカウンターは、以下の要素に対してインクリメントされます。
vs-counter-fig- 内部に
imgやpicture要素を持つfigure要素、もしくはfigクラスが設定されたfigure要素 vs-counter-tbl- 内部に
table要素を持つfigure要素、もしくはtblクラスが設定されたfigure要素 vs-counter-citecite-itemsクラスが設定されたol要素の子要素であるli要素
それぞれのカウンターの番号を表示するには、以下のCSS変数を設定します。図と表のカウンター番号を表示するためには、figure要素の中にfigcaption要素、もしくはtable要素の中にcaption要素を用意する必要があります。
:root {
  --vs-crossref--marker-display: inline;
}
文中に図表を参照する番号を挿入するには、以下のように空のa要素を追加します。hrefには参照したい図表のid属性、data-refにはfigやtblなどのカウンターの種類を指定します。
<a href="#fig-1" data-ref="fig"></a>
ページ・ドキュメント・チャプターカウンター  
Vivliostyleでは、ページ番号を表すための特別なカウンターpageが最初から使えるようになっていますが、Vivliostyle Themeではこれ以外にもドキュメント単位やチャプター単位のカウンターが用意されています。
Vivliostyle CLIでは、入力として単一のMarkdownファイルを指定する方法以外にも、vivliostyle.ファイルを使って複数のMarkdown/vs-counter-docが利用できます。また、特別なページであるchapterやpartを用意することで、
| カウンター名 | 説明 | 
|---|---|
vs-counter-doc | 
ドキュメントのカウンター | 
vs-counter-chapter | 
chapterページのカウンター | 
vs-counter-part | 
partページのカウンター | 
chapterおよびpartは、html要素かbody要素にchapter、partというクラス名を設定するか、role属性にdoc-chapter、doc-partを設定することでそのページがchapter/
---
class: chapter
---
これらのカウンターを使って、以下のようにページマージンなどのcontentに追加することができます。
:root {
  /* ページ上部に節番号、章番号、ドキュメントのタイトルを表示 */
  --vs-page--mbox-content-top-center: counter(vs-counter-chapter) '.' counter(vs-counter-doc) ' ' env(doc-title) ;
  /* ページ下部にページ番号を表示 */
  --vs-page--mbox-content-bottom-center: counter(page);
}
自分でカウンターを追加する
前に述べた通り、直接counter-resetを設定すると他のcounter-resetの設定を上書きしてしまうおそれがありました。そのため、Vivliostyle Themeでは自分でカウンターを追加するためのCSS変数も用意しています。
:root {
  /* 各ドキュメントのrootでリセットされるカウンターを設定 */
  --vs-document-root-counter-reset: my-document-counter;
  /* 最初のページでリセットされるカウンターを設定 */
  --vs-first-page-counter-reset: my-chapter-counter;
}
--vs-document-root-counter-resetと--vs-first-page-counter-resetで指定されたカウンターは、それぞれ:rootや@page :firstが出現する箇所でリセットされるようになっています。このとき、他のカウンターリセットを上書きすることはないため、この変数を介して指定することで、安全にカウンターをリセットすることができます。
テーマを作成・公開する 
CSS変数を使ったVivliostyle Themeのカスタマイズに慣れてきたら、カスタマイズした内容を実際に新しいテーマとして公開することを検討してみてください。以下のコマンドを実行することで、ローカル環境にテーマのテンプレートを作成することができます。
$ npm create vivliostyle-theme <作成するテーマの名前>
作成されたテンプレートには、以下のようなファイルが用意されています。
vivliostyle-theme-my-book ├── LICENSE ├── README.md ├── example ├── package-lock.json ├── package.json ├── theme.css └── vivliostyle.config.js
ファイル構成からも分かる通り、Vivliostyle Themeのテーマファイルはnpmのパッケージとして配布することができます。package.に対して、以下のようにvivliostyleプロパティを追加することで、そのパッケージがVivliostyle Themeであることを示しています。これらの設定の詳細は、公式のドキュメント も参考にしてください。
{
  "vivliostyle": {
    "theme": {
      "name": "My book theme",
      "author": "spring-raining",
      "style": "./theme.css",
      "category": "novel",
      "topics": []
    }
  }
}
テーマの作成が完了したら、通常のnpm package公開の手順に従ってPublishをしてください。パッケージがnpmレジストリに登録されると、公開したテーマの名前で誰でも利用することができるようになります。また、package.vivliostyle-themeという名前のキーワードを追加しておくことで、そのテーマを利用可能なVivliostyle Themeとしてリストアップさせることができます。例えばCreate Bookでは、リストアップされたテーマの中から選ぶことで、そのテーマがあらかじめ設定されたVivliostyleプロジェクトのひな形を簡単に作ることができます。
まとめ
Vivliostyle Themeについて、そのままテーマを適用する方法をはじめ、テーマをカスタマイズしたり、カスタマイズした内容を別のテーマとして公開する方法について紹介しました。これまでVivliostyleに興味を持つものの、CSSによるページデザインについて敷居が高いと感じていた人にとって、Vivliostyle Themeはそのハードルを下げる存在になると思います。
さらに、CSS変数を活用したBaseテーマの導入により、Vivliostyle Themeを使う人だけでなく作る人にとっても開発環境が改善されました。共通のCSS変数を参照することで、テーマの利用者が後からカスタマイズしたり、カスタマイズしたテーマを新たな派生テーマとして公開するといったように、Baseテーマを起点としたエコシステムが構築されるようになりました。Vivliostyle Themeを作成する上でBaseテーマを利用することは必須ではありませんが、このようなメリットを考えると、個人的にはぜひBaseテーマのCSS変数を活用することをおすすめしたいと思います。
