新しくなった Vivliostyle Themes のカスタムテーマを公開する
はじめに
Vivliostyle[1] は HTML と CSS を用いて本を制作する CSS 組版ソフトウェアで、「CSS 組版」という名の通り本のレイアウトや組版設定などを CSS で実現しています。
そしてレイアウトや組版設定などを本の種類に応じた汎用的なものとしてパッケージ化し、テーマとして公開しているのが Vivliostyle Themes[2] です。
2023 年 8 月 10 日、Vivliostyle Themes が大幅に刷新されてリリースされました。
新テーマの CSS を見たところ、旧テーマで課題に感じていた構造の複雑さが解消されてシンプルになっており、カスタマイズ自体は旧テーマよりやりやすくなると感じました。
しかし、実際にカスタマイズを始めてみると、公開されてまだ日も浅く、悩むポイントがいくつかありました。
本記事では、これから新テーマをカスタマイズする・したいという方をターゲットとして、次の内容についてソースコードのサンプルや事例をもとに紹介します。
- 旧テーマと新テーマの変更点
- 新テーマをベースにカスムテーマを作成する
- カスタムテーマを npm パッケージとして公開する
制作環境
ツール | バージョン | 備考 |
---|---|---|
macOS[3] | Ventura 13.5.2 | |
Vivliostyle CLI[4] | 8.1.2 | VivliostyleのCLI |
Vivliostyle Themes | 1.0.0 | Vivliostyleの公式テーマ |
Node.js | 18.18.0 | |
npm | 10.1.0 |
旧テーマと新テーマの変更点
Vivliostyle Themes の旧テーマと新テーマの大きな変更点として、旧テーマでは Sass[5] を使ってレイアウトや組版設定を定義していたのに対して、新テーマでは CSS と CSS Variables(CSS 変数)[6] を使うように変更されました。
旧テーマでは、SCSS ファイルにレイアウトや組版設定の定義、それらに使用する値の変数定義を行い、そのファイルをコンパイルして CSS ファイルを生成するため、定義が記述されているファイルと HTML に読み込まれるファイルとが異なり、編集や確認が複雑になっています。
一方、新テーマではレイアウトや組版設定の定義、それらに使用する値の変数定義が直接 CSS ファイルに記述されているため、編集や確認が行いやすくなりました。
CSS Variables を採用した経緯やモチベーションなどの詳細は、公式ブログ「新しい Vivliostyle Themes のご紹介」[7]を参照ください。
新テーマをベースにカスムテーマを作成する
この節では、次の内容について紹介します。
- カスタマイズの方針
- 新テーマを利用する
- カスタマイズするための前準備をする
- 新テーマのカスタマイズ方法
- カスタマイズ事例の紹介
カスタマイズの方針
新テーマで行うカスタマイズの方針として、既刊の『ゆめみ大技林』で行った旧テーマのカスタマイズと同様のカスタマイズを、新テーマをベースにして行うことを目標にしました。
旧テーマでカスタマイズした内容は「Vivliostyle の公式テーマをカスタマイズして、ゆめみ大技林 '22 のテーマを作った」[8]という記事で紹介していますので、あわせて参照ください。
新テーマを利用する
新テーマを利用するシンプルな方法は、Create Book
[9] を使って新しく執筆環境を作成することです。次のコマンドを実行することで、新テーマを利用可能な執筆環境が作成されます。
$ yarn create book <directory>
# or
$ npm create book <directory>
上記コマンドを実行すると Description
、Author name
、Author email
、License
、choose theme
の入力を求められ、このうち choose theme
で選択したものがベースとなる新テーマです。
すでに執筆中の原稿がある、または執筆用のテンプレートが用意されているなどの理由で新しく執筆環境を用意することが難しい場合は、vivliostyle.config.js
の theme
の値を変更することで新テーマを利用できます。
module.exports = {
...
theme: '@vivliostyle/theme-techbook@^1.0.0',
...
}
本記事では、どちらの場合もベースのテーマとして技術同人誌向けのテーマである @vivliostyle/theme-techbook
を選択したものとします。
カスタマイズするための前準備をする
新テーマを利用できる状態になったので、続いてカスタマイズするための前準備をします。
カスタマイズ用の CSS ファイルを作成する
カスタマイズには、公式テーマの CSS に定義された CSS 変数の値の上書き、もしくは新たに CSS や CSS 変数の追加が必要です。ここでは book
ディレクトリの配下に theme
ディレクトリを作成し、その配下にカスタマイズ用の theme.css
を作成するものとします。
$ cd book
$ mkdir theme && cd $_
$ touch theme.css
カスタマイズ用の CSS ファイルをテーマとして読み込む
作成した CSS ファイルをテーマとして読み込むように vivliostyle.config.js
の theme
の値を変更します。
module.exports = {
...
theme: [
'@vivliostyle/theme-techbook',
'theme/theme.css' // ここに作成したCSSファイルのpathを記述する
], ...
}
上記の変更により、ビルドを実行すると theme.css
に記述された CSS がテーマとして反映されます。
新テーマのカスタマイズ方法
テーマをカスタマイズするときにどの CSS 変数を上書きすればよいかですが、基本的には公式テーマの CSS を読み解きながら実際に値を変更して試すしかないです。一部の CSS 変数は @vivliostyle/theme-base
の README[10]に掲載されているため、それらをとっかかりとして調べるとよいでしょう。
新しく CSS を追加する場合も同様に公式テーマの CSS を読み解くことから始めましょう。
カスタマイズ事例の紹介
ここからは筆者が行ったカスタマイズ事例を、ソースコードとともに紹介します。
実際に本として組版されたときにどう見えるかは、いまお手にとっていただいている(もしくは画面に表示されている)『ゆめみ大技林 '23 (2)』が参考になるかと思います。
天・地・のど・小口のマージンを調整する
天・地・のど・小口とは、本を見開きとして開いた状態で見たときの各方向のマージンを指します。
名称 | マージンの場所 |
---|---|
天 | 上方向 |
地 | 下方向 |
のど | 内側(綴じられている)方向 |
小口 | 外側(綴じられていない)方向 |
この数値は @vivliostyle/theme-techbook
の CSS を参考にして調整しました。なお、綴じ方、ページ数などによって数値を変えることが一般的なため、紹介した数値が正解というわけではありません。
:root {
/*
* page's margins
*/
/* 天 */
--vs-page--margin-top: 20mm;
/* 地 */
--vs-page--margin-bottom: 25mm;
/* のど */
--vs-page--margin-inner: 17mm;
/* 小口 */
--vs-page--margin-outer: 17mm;
}
本文の文字サイズを調整する
本文とは、本の大部分を占める通常の文章のことを指します。
旧版テーマをカスタマイズしたものと同様の文字サイズになるように調整しました。
:root {
/*
* base font-size
*/
/* テーマ全体のベースの文字サイズ */
--vs-font-size: 10px;
/* 印刷用レイアウトの文字サイズ */
--vs-font-size-on-print: var(--vs-font-size);
}
見出しの文字サイズと行間を調整する
行間とは、行と行の間のマージンを指します。
各見出しの文字サイズと行間を次のように調整しました。
旧版テーマでは見出し上部にマージンを設ける調整をしていましたが、新テーマでは公式テーマ側の見直しもあり、特段マージンを設ける必要はないと判断してマージンを設けていません。
:root {
/*
* header
*/
--vs--heading-line-height: 1.3;
--vs--h1-font-size: 2.2em;
--vs--h2-font-size: 1.6em;
--vs--h3-font-size: 1.3em;
--vs--h4-font-size: 1.15em;
--vs--h5-font-size: 1em;
--vs--h6-font-size: 0.83em;
}
見出しをなるべく追い込むように調整する
新テーマでは、見出しをなるべく次のページに送り込むように定義されています。この状態で既刊の記事を流し込んで確認したところ、見出しが登場した際に改ページが行われることで本文がページの半分ほどしかないページが続いたり、改ページによるページ数増加が発生したりしました。
本文がページの半分ほどしかないページが続いた際の読みづらさや、ページ数増加による印刷代増加を避けるため、見出しをなるべく前のページに追い込むように調整しました。
:root {
/*
* header page break
*/
--vs-section--h1-break-before: inherit;
--vs-section--h2-break-before: auto;
--vs-section--h3-break-before: auto;
--vs-section--h4-break-before: auto;
--vs-section--h5-break-before: auto;
--vs-section--h6-break-before: auto;
}
ノンブルや柱の文字サイズを調整する
ノンブルとは各ページにあるページ番号を表示したもの、柱とは各ページにある誌名や章タイトルを指します。
柱は章タイトルなど比較的長い文章を表示することが多いため、領域内に収める目的で本文の文字サイズより小さくしています。ノンブルは柱の文字サイズと揃えました。
:root {
/*
* page margin box's font size
*/
/* 本文サイズより 1px 小さくした */
--vs-page--mbox-font-size: calc(var(--vs-font-size) - 1);
}
コードブロックを調整する
新テーマでは、コードブロックがページをまたいだ際に網掛け内の天地のマージンが一定ではなく読みづらさを感じたので、マージンが一定になるように調整し、あわせて文字サイズや行間も調整しました。
解決できていない問題として、「display: flex
とした場合、キャプション付きのコードブロックに対して 1 ページ内に収まらない分量の長いコードを挿入すると、コードブロックがページ下部を突き抜けてしまう」というものがあり、キャプションありの場合は display: block
にすることで回避しています。
:root {
/*
* code block
*/
/* 等幅フォントの行間 */
--vs--monospace-line-height: 1.3;
/* コードブロック関連の文字サイズ */
--vs--pre-font-size: 95%;
}
/*
* code block
*/
@media print {
pre[class*='language-'] {
/* コードブロックが複数ページにまたがったときに別ボックスとすることで、天地のマージンを一定にする */
box-decoration-break: clone;
}
}
figure[class*='language-'] {
/*
* キャプション付きのコードブロックに対して1ページ内に収まらない分量の長いコードを挿入すると、
* コードブロックがページ下部を突き抜けてしまうので、
* キャプションありの場合は flex にしない
*/
display: block;
}
URLに対して自動で生成される脚注表記を無効化する
脚注とは、本文の下部に表示される注記のことを指します
新テーマでは、URL に対して自動で脚注表記が生成されるのですが、著者自身で表記の有無をコントロールするほうが扱いやすいと感じたため、次のように調整して無効化しました。
/*
* footnote-external-link
*/
@media print {
/* URL に対して自動生成された脚注表記を非表示にする */
:not(.footnote) > a[href^='http']::before {
display: none;
}
:not(.footnote) > a[href^='http']::after {
/* URL の後ろに付与された脚注番号を非表示にする */
display: none;
}
}
脚注の文字サイズを調整する
脚注の文字のサイズを本文より小さくなるように調整しました。
:root {
/*
* footnote's font size
*/
--vs-footnote--font-size: calc(var(--vs-font-size) - 1);
}
後注の文字サイズを調整する
後注とは、本文の最後に表示される注記のことです。脚注と同じ文字サイズになるように調整しました。
:root {
/*
* endnote contents's font size
*/
--vs-endnote--section-font-size: calc(var(--vs-font-size) - 1);
}
段落間のマージンを調整する
旧テーマと新テーマを比較したときに、新テーマは段落間のマージンが広すぎると感じたので調整しました。
:root {
/*
* p
*/
/* マージンを本文と同サイズにする */
--vs--p-margin-block: var(--vs-font-size);
}
目次の表記を調整する
新テーマでは目次の章タイトル部分に連番が表示されなくなったので、旧テーマを参考に連番が表示されるように調整しました。
:root {
/*
* toc
*/
/* 番号のあとにピリオドを追加する */
--vs-toc--marker-content: counter(vs-counter-toc) '.';
/* 番号を表示する */
--vs-toc--marker-display: block;
/* 番号を右揃えにする(番号の桁数が異なったときに右でそろえるため) */
--vs-toc--marker-text-align: end;
}
/*
* toc
*/
:is(#toc, [role='doc-toc']) li::before {
/* 番号と章タイトルの間のマージンをピリオド分広げるための調整 */
inset-inline-start: calc(var(--vs-toc--ol-indent-size) * -1.2);
}
コードブロック内の String 型の文字色を調整する
新テーマでは、コードブロックの中の String 型の文字色が白っぽい色になっており、公式テーマの CSS を確認したところ、変数の値代入を重複して行っていたことが不具合の原因でした。
この不具合は修正されたものの、執筆時点ではまだリリースされていないため、ワークアラウンドとして意図した色になるように調整しました。
:root {
/*
* prism
*/
--vs-prism--color-string: #a6e22e;
}
<!-- TODO: sass版とそんなに変わらないので削る予定
章タイトル周りに飾りを入れる
Sass版で章タイトル周りに飾りをいれており、CSS変数版でも似たようなレイアウトになるようにしました。
:root {
--dg--chapter-title-decoration-color: #27ae60;
}
/*
* chapter layout
*/
.content > section > h1 {
/* 執筆した原稿には <body class='content'> が指定されており、そのクラス配下の h1 を非表示にする */
display: none;
}
div.doc-header {
border-left: 4pt solid;
border-bottom: 2pt solid;
/* border-colorの値を上書きしないとborder-left、border-bottomの色が意図した色にならない */
border-color: var(--dg--chapter-title-decoration-color);
padding-top: 5pt;
padding-left: 14pt;
padding-bottom: 10pt;
margin-bottom: 20pt;
position: relative;
h1 {
display: block;
}
}
div.doc-header::before {
content: "";
position: absolute;
width: 100%;
height: calc(100% + 2pt);
border-left: 2pt solid;
/* border-colorの値を上書きしないとborder-left、border-bottomの色が意図した色にならない */
border-color: var(--dg--chapter-title-decoration-color);
top: 0pt;
left: 2pt;
}
div.doc-author {
text-align: right;
}
この章タイトル周りの飾りを適用するには、Markdownに次のような加工が必要、かつMarkdown内で h1
は <div class="doc-header">
内の一箇所だけにする制約があります。
---
class: content
---
<div class="doc-header">
<h1>レノくんはクマ</h1>
<div class="doc-author">macneko</div>
</div>
レノくんはクマ
==
-->
<!-- TODO: ここも削除予定
任意の位置で改ページ可能なCSSを追加する
『Web技術で「本」が作れるCSS組版Vivliostyle入門』[11]を参考にして、CSSを追加しました。
/*
* page break
*/
hr.page-break {
break-after: page;
visibility: hidden;
}
-->
以上が主なカスタマイズ事例となります。
カスタマイズしたテーマをnpmパッケージとして公開する
がんばって作ったテーマを自分だけが利用するのはもったいないので、カスタムテーマとして公開して自分以外の執筆者に利用してもらえるようにしましょう。
本節では、作成したカスタムテーマを npm パッケージとして公開する方法を紹介します。
なお、本記事で紹介したカスタマイズテーマは「vivliostyle-theme-macneko-techbook」[12]として公開していますので、興味のある方はぜひご利用ください。本誌もこのテーマを利用して制作されています。
npmパッケージを公開するためにやること
npm パッケージを公開する手順は、次のとおりです。
-
create-vivliostyle-theme
を利用して、カスタムテーマを作成する - npm のアカウントを作成してログインする
- npm パッケージを公開する
筆者が「vivliostyle-theme-macneko-techbook」を公開したときの手順にそって説明していきます。
create-vivliostyle-theme
を利用して、カスタムテーマを作成する
テーマの雛形を作成する
create-vivliostyle-theme
[13]とは、Vivliostyle のテーマの雛形を作成するためのツールです。
コマンドを実行すると、テーマの雛形作成に必要な情報の入力を求められ、すべて回答すると雛形が作成されます。
# `<your-theme-name>` には作成するテーマの名前を入力する必要があり、ここでは `macneko-techbook` と入力したものとして進めます。
$ npm create vivliostyle-theme <your-theme-name>
? Description <説明>
? Author name <Author名>
? Author email <Authorのemail address>
? License <ライセンス。リストから選択する>
? choose category <テーマのカテゴリ。リストから選択する>
成功すると次のメッセージが出力されます。
Successfully created <your directory>/vivliostyle-theme-maneko-techbook
1. cd vivliostyle-theme-maneko-techbook
2. edit theme.css
3. publish to npm ($ npm publish)
雛形を編集してカスタムテーマを作成する
続いて、雛形として生成されたファイルを編集していきます。雛形では @vivliostyle/theme-base
がベースとなっていますが、@vivliostyle/theme-techbook
をベースとするため、vivliostyle.config.js
を変更します。
まず dependencies
に @vivliostyle/theme-techbook
を追加します。
dependencies
に追加することで、ビルド時に @vivliostyle/theme-base
および @vivliostyle/theme-techbook
がインストールされます。
{
...
"dependencies": {
- "@vivliostyle/theme-base": "latest"
+ "@vivliostyle/theme-base": "latest",
+ "@vivliostyle/theme-techbook": "latest"
},
...
}
次に @vivliostyle/theme-techbook
を vivliostyle.config.js
の theme
に追加します。
module.exports = {
...
- theme: ['node_modules/@vivliostyle/theme-base', '.'],
+ theme: [
+ 'node_modules/@vivliostyle/theme-base',
+ 'node_modules/@vivliostyle/theme-techbook',
+ '.'
+ ],
...
};
最後に雛形として生成されている theme.css
の内容を任意の CSS に書き換えればカスタムテーマの完成です。
注意点として、インストールしたベーステーマの CSS 変数や CSS を上書きしたい場合は、次の例のように対象の CSS ファイルを theme.css
に import する必要があります。またその際のファイルパスは workspaceDir
(ビルドしたファイル群が展開されるディレクトリ)内の theme.css
から見た相対パスになります。
@import url(../@vivliostyle/theme-base/theme-all.css);
@import url(../@vivliostyle/theme-base/css/lib/prism/base.css);
@import url(../@vivliostyle/theme-base/css/lib/prism/theme-okaidia.css);
@import url(../@vivliostyle/theme-techbook/theme.css);
npm のアカウントを作成してログインする
npm パッケージを公開するためには npm のアカウントが必要になります。
アカウントを作成したことがない場合は、https://www.npmjs.com/ からアカウントを作成しましょう。
次のコマンドを実行して作成済のアカウントにログインします。
$ npm login
ログインに成功したかどうかは、次のコマンドで確認できます。
$ npm whoami
コマンド実行後にアカウント名が出力されたらログインに成功しています。
npm パッケージを公開する
GitHub にリポジトリを作成していなければ作成してから、すでに作成済の場合はリポジトリのディレクトリに移動し、次のコマンドを実行します。
$ npm publish
パブリッシュに成功したか確認するには、https://www.npmjs.com/package/<your-package-name>
の <your-package-name>
の部分を自分のパッケージ名に変更し、ブラウザで該当 URL を表示します。次の画像のようにパッケージの詳細画面が表示されれば、公開完了です。
以上で作成したカスタムテーマを npm パッケージとして公開できました。
おまけ:Vivliostyle へのコントリビュート
本記事で紹介したカスタムテーマを作成する過程で、Vivliostyle Themes に 2 件の Pull Request を送り、無事にマージされました。
Vivliostyle のコントリビュータの末席に名を連ねてはいる(本記事内でも紹介した旧テーマのカスタマイズ記事がきっかけで声をかけていただき参加した)ものの、Web 系の技術を普段の業務であまり触れる機会がないこともありなかなか貢献できずにいたので、今回少しでも貢献することができてよかったです。
おわりに
本記事では新しくなった Vivliostyle Themes のカスタマイズ方法や、カスタムテーマを npm パッケージとして公開する方法を紹介しました。
この記事をきっかけに、Vivliostyle を使った執筆事例やカスタムテーマの作成事例、それらの事例を紹介する記事などが増えると嬉しいです。
それではみなさま、よい執筆ライフをお送りください!
-
Windows 環境での動作確認は行っていません ↩︎
-
https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties ↩︎
-
https://vivliostyle.org/ja/blog/2023/04/23/intro-new-themes/ ↩︎
-
https://github.com/vivliostyle/themes/blob/main/packages/%40vivliostyle/theme-base/README.md ↩︎
-
https://www.npmjs.com/package/vivliostyle-theme-macneko-techbook ↩︎
-
https://github.com/vivliostyle/themes/tree/main/packages/create-vivliostyle-theme ↩︎
Discussion