Vivliostyle v2.36.0(CLI v9.8.0)では新たなCSS関数target-text()が追加されました(私が実装しました!) これはCSS Generated Content Module Level 3で定義されている関数で、指定したIDを持つ要素の文字列をcontentプロパティで使用することができます。図版番号や別の箇所の見出しを本文に転記したり、目次を作成したりする際に役立つ機能です。まずはサンプルをご覧ください。
style.css
@page {
size: A5;
}
:root {
counter-reset: chapter;
}
* {
font-family: serif;
}
h2 {
counter-reset: img;
}
h2::before {
counter-increment: chapter;
content: "第" counter(chapter) "章";
margin-inline-end: 1em;
}
figcaption::before {
counter-increment: img;
content: "図" counter(chapter) "." counter(img);
margin-inline-end: 1em;
}
.xref::before {
content: target-text(attr(href url));
}
.xref-before::before {
content: target-text(attr(href url), before);
}
.toc-entry::before {
content: target-text(attr(href url), before) "\2003" target-text(attr(href url)) leader(dotted) target-counter(attr(href url), page);
}
manuscript.md
---
lang: ja
link:
- rel: stylesheet
href: style.css
---
<nav>
- <a class="toc-entry" href="#chapter-1"></a>
- <a class="toc-entry" href="#chapter-2"></a>
</nav>
## 章見出し1 {#chapter-1}
Aについて(<a class="xref-before" href="#img-a"></a>)……
<figure>
<figcaption id="img-a">Aの概要</figcaption>
<img width=80% src="data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='640' height='480' viewBox='0 0 640 480'><rect x='0.5' y='0.5' width='639' height='479' fill='none' stroke='black'/><line x1='0' y1='0' x2='640' y2='480' stroke='black'/><line x1='640' y1='0' x2='0' y2='480' stroke='black'/></svg>" />
</figure>
Bについては<a class="xref" href="#chapter-2"></a>を参照のこと。
## 章見出し2 {#chapter-2}
Bについて……
Aについては<a class="xref" href="#chapter-1"></a>を参照のこと。
target-text()の基本的な使い方は次の通りです。
- 文字列を取り出したい要素に
id属性を与える - 文字列を使いたい箇所に対象のIDを参照する
a要素を配置する -
a要素の::before/::after疑似要素のcontentでtarget-text(attr(href url))を使用する
上の例では、別の章を参照する際に見出し文字列をハードコーディングせず、xrefクラスのa要素を用いています。参照先を変更するとtarget-text()関数で作られた箇所も連動するので、参照の修正漏れが起こりません。
target-text()関数では、カウンターで作って疑似要素に含めた文字列も取り出すことができます。たとえば、図表には通常「図1.2」などと番号を振ります。ここで「1」や「2」はCSSカウンターで作り、キャプション要素の::before疑似要素として表示するのが基本的なテクニックです。xref-beforeクラスでは、figcaption要素の::before疑似要素から「図1.1」の文字列を取り出しています。
さらにこれらは組み合わせることも可能です。toc-entryクラスでは章の見出しと::before疑似要素の文字列、さらにleader()関数とtarget-counter()関数を組み合わせて、空のa要素から実用的な目次を作っています。
なおtarget-counter()にはリンクを収集する機能はありません。項目の収集や整列はCSS組版の外で、PythonなりJavaScriptなりで行う必要があります。収集のためにどうせ前処理するならテキストも取ってくればtarget-text()は無用なのでは、というと部分的にはそうです。私が使うなら、目次ではtarget-text()がシンプルで機能十分、索引では整列のためにスクリプト側でテキストを収集したいところです。ここの責務の別やバランス感覚はhidarumaさんの記述がためになります。今回の話題だとこのあたりです。
