Vivliostyle.js における Web 標準 CSS サポートの大改善

村上真雄

CSS組版なら、Web標準のCSS機能は使えて当然でしょ

CSS 組版の大きなメリットは、Web の標準の CSS の知識があれば、自分でスタイルシートを作ることが簡単にできることです。 標準の CSS を学ぶための材料はたくさんあります。MDNサイトのCSS入門などお薦めです。

でも、せっかく Web の標準の CSS を覚えたのにそれを CSS 組版で使おうとしたら、CSS 組版エンジンではその CSS 機能は使えないとなったら、CSS 組版へのモチベーションがダダ下がりになりますよね。Web の標準の CSS 機能は CSS 組版でも使えて当然のはずでしょう。(アニメーション機能など、印刷での再現が無理なものを除けば)

しかし、それが問題でした。

これまで不満だったVivliostyle.jsでのWeb標準CSSサポート

CSS 組版エンジン Vivliostyle.js の大きな特徴は、標準の Web ブラウザ上で動く JavaScript プログラムとして実現されており、CSS でのレイアウトの機能の多くはブラウザでサポートされている CSS の機能を利用して、それだけでは足りないところを独自に実装しているということです。

このような方式なので、Vivliostyle.js がサポートする CSS の機能はブラウザがサポートする CSS の機能を包含するスーパーセットであるべきなのですが、現実はそうなっていなくて、ブラウザでは標準で使えるのに Vivliostyle.js では使えない機能が多々あるという残念な問題がありました。

最近までVivliostyle.jsで使えなかったCSSの機能の例

など。(これらは最近やっと使えるようになりました!)

ブラウザのCSS機能をそのまま活かすのが簡単でない理由

もしブラウザに CSS プロパティや CSS ルールの構文を拡張するための標準のしくみがあれば、ブラウザの CSS 機能をそのまま保ちながら足りない CSS 機能を追加できそうですが、残念ながらまだそれがありません(CSS Houdiniというブラウザの API のセットの開発が進められていて、将来的にはそれが役に立ちそうですが、現時点ではまだ使えません)。そのため Vivliostyle.js では、CSS の機能を拡張するために、CSS の構文解析やカスケーディングの処理、CSS プロパティやその値の指定が正しいかどうかを判定する処理などを自前で行う必要がありました。

Vivliostyle.js のベースになっているPeter Sorotokin氏によるEPUB Adaptive Layout実装が作られたのは 2013 年ごろです。Vivliostyle.js での CSS の処理は、この古いプログラムを引き継いで、CSS 組版に必要な CSS の機能を拡充させていったものです。それから今まで CSS の標準仕様とブラウザでのそのサポートはだいぶ進んでいるのに、Vivliostyle.js でそれをすぐに反映させることができず、だいぶギャップが生じていました。その結果として、ブラウザで使える最新の CSS の機能がなかなか Vivliostyle.js で使えるようにならない問題が起きていたのです。

ブラウザで使えるCSSプロパティと値は基本的にすべて使えるようにしました!

最近の Vivliostyle.js の更新(v2.16 と v2.17)で、これまでの CSS の処理を見直して、ブラウザで使える CSS プロパティと値は基本的にすべて使えるように改良しました。Vivliostyle.js の中に CSS の構文解析やカスケーディングの処理、有効な CSS 指定かどうか判定する処理があるのは変わりませんが、Vivliostyle.js の中で定義されていない CSS プロパティやプロパティの値があったとき、それがブラウザでサポートされているものならば有効なプロパティ指定として生かすようにしたのです。

今後は、ブラウザでサポートされている CSS プロパティやその値が機能しなかったら、それはバグと言えるのでVivliostyle.jsにバグ報告ください

これでCSS Grid Layoutが使える!

CSS Grid Layoutのデモを Vivliostyle CLI の preview で表示する例:

vivliostyle preview https://webkit.org/demos/css-grid/
CSS Grid Layout ExamplesをVivliostyle CLIのpreviewで表示

このように、これまで Vivliostyle で使えなかった CSS Grid Layout が使えるようになりました。

CSS変数をサポートしました!

CSS変数(カスタムプロパティ)は、もう何年も前にブラウザで利用可能になって普及していますが、Vivliostyle では使えない状態でした。CSS 組版のスタイルシートをカスタマイズしやすくするために、これがないと不便です。Vivliostyle.js v2.17 で、やっと使えるようになりました!

CSS 変数は、任意のスタイルルールの中で使用できて、また、ページを定義する @page {...} の中でも使用できます。次の簡単な例をご覧ください。

:root {
  --page-width: 148mm;
  --page-height: 210mm;
  --page-margin: 20mm;
  --page-header: "My Report";
  --page-footer: counter(page) " / " counter(pages);
}
@page {
  size: var(--page-width) var(--page-height);
  margin: var(--page-margin);
  @top-center {
    content: var(--page-header);
  }
  @bottom-center {
    content: var(--page-footer);
  }
}

まだ残っているCSS標準サポートの課題

CSS プロパティのサポートについてはだいぶ改善できました。しかし、最新のブラウザで使えるのに Vivliostyle でサポートできてない CSS の機能はまだあります。以下のものなどです:

:is()、:has()、:where() 擬似クラスなどSelectors Level 4サポート(予定)

CSSセレクターについて、Vivliostyle.js ではSelectors Level 3の仕様が実装されてますが、最近のブラウザではSelectors Level 4の仕様の実装が進んでます。それが使えるようになれば、いろいろな条件によってスタイルを変えることがより簡単にできるようになります。

とくに :has() 擬似クラスが使えると、画期的に便利になります。従来の CSS セレクターでは、親の要素や前の要素が何であるかによる要素の選択はできても、子要素や後につづく要素が何であるかによって要素を選択できないことが不便でした。それができるようになります!

:has() 擬似クラスの使用例:

section:has(section) {
  /* 内側にも section が存在する section のスタイル */
}
h1:has(+ p) {
  /* 段落 p があとに続く見出し h1 のスタイル */
}

関連 Vivliostyle.js Issues:

箇条書きのマークを指定する ::marker擬似要素

::marker擬似要素は箇条書きの記号や番号のを指定できる擬似要素 ::marker が使えると、箇条書きのスタイルをより自由にできます(これまでは代わりに ::before 擬似要素を使って工夫する必要がありましたが、より簡単になります)。

例:箇条書きの番号の色とフォントを変える

<style>
ol > li::marker {
  color: blue;
  font: italic 200% sans-serif;
}
</style>
<ol>
  <li>あああああ</li>
  <li>いいいいい</li>
  <li>ううううう</li>
</ol>

この結果は次のようになるはず:

1. あああああ
2. いいいいい
3. ううううう

例:番号付きの NOTE

<style>
p.note {
  margin-left: 5em;
  display: list-item;
  counter-increment: note-counter;
}
p.note::marker {
  content: "NOTE " counter(note-counter) ": ";
}
</style>
<p class="note">あああああ</p>
<p class="note">いいいいい</p>
<p class="note">ううううう</p>

この結果は次のようになるはず:

NOTE 1: あああああ
NOTE 2: いいいいい
NOTE 3: ううううう

関連 Vivliostyle.js Issue:

カウンタースタイル定義機能 @counter-style

箇条書きの番号、ページ番号、章番号など自動連番に使うカウンタースタイル(list-style-type プロパティや counter()関数に指定する)は、標準で以下のものなどが使えます:

  • decimal (1, 2, 3, …)
  • decimal-leading-zero (01, 02, 03, …, 98, 99)
  • lower-roman (i, ii, iii, iv, v, …)
  • upper-roman (I, II, III, IV, V, …)
  • lower-alpha (a, b, c, …)
  • upper-alpha (A, B, C, …)
  • lower-greek (α, β, γ, …)
  • cjk-decimal (一, 二, 三, …, 一〇, 一一, …)
  • japanese-informal (一, 二, 三, …, 十, 十一, …)
  • japanese-formal (壱, 弐, 参, …, 壱拾, 壱拾壱, …)

など。(詳しくはCSS list-style-typeプロパティを参照)

標準で定義されていないカウンタースタイルを自分で定義できる@counter-styleが使えるようになるとより便利になります。

例:カウンタースタイル circled-lower-latin (ⓐ, ⓑ, ⓒ, …)を定義

@counter-style circled-lower-latin {
  system: alphabetic;
  speak-as: lower-latin;
  symbols: ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ
           ⓝ ⓞ ⓟ ⓠ ⓡ ⓢ ⓣ ⓤ ⓥ ⓦ ⓧ ⓨ ⓩ;
  suffix: " ";
}

関連 Vivliostyle.js Issue:

カスケードレイヤー @layer

競合するスタイルルールがあるとき、どのスタイルが適用されるかは、指定される順番や CSS セレクターの詳細度で決まります(詳しくは MDN の「CSSカスケード入門」参照)。しかし、ベースのスタイルシートに対してスタイルルールを追加して特定の要素のスタイルを変えたいときなど、CSS セレクターの詳細度に気をつけないと思うようにスタイルを上書きできないのが面倒なところです。これを解決するのが、最近のブラウザで利用可能になったカスケードレイヤー @layerです。

関連 Vivliostyle.js Issue:

組版に役に立つCSS機能の追加実装も進めてます!

ここまでは、最新のブラウザで使える標準の CSS 機能を Vivliostyle.js でサポートすることについて書きました。このブラウザ標準の CSS サポートを進めることと、それで足りない組版のための CSS 機能の実装を進めることは、Vivliostyle.js を CSS 組版エンジンとしてよりよいものにするためにどちらも必要です。

Vivliostyle.js がサポートしている CSS 機能は、Vivliostyle のドキュメント「サポートするCSS機能」にあります。そのうち Vivliostyle.js で追加実装した CSS 仕様の主なものは以下です:

以下は、ページメディア用 CSS の機能でまだ実装できていない主なもの(Vivliostyle.js Issues にあるもの):

Vivliostyle.jsまだまだ開発途上なのでどうぞよろしく!

以上、Vivliostyle.js の CSS 仕様サポート改善の取り組みについてでした。ここで取り上げていない課題(バグを直すことなど)もたくさんあり、まだまだ開発途上です。

Vivliostyle を使っていると、思い通りの組版結果にならなかったり(それはバグのせいかもしれない)、機能が足りないと感じることがあると思います。ぜひ Issue 登録してください。そのとき、まずすでにその問題が Issue に登録されていないか探してみてください。そして、すでにある Issue だったら、自分もその問題で困っていることなど、コメントをつけたりしてくれると、こちらもその Issue に取り組むモチベーションが上がります。

どうぞよろしく!