理系学生日記

おまえはいつまで学生気分なのか

CSSで目次を含めた章番号を自動的に採番・表示する

今回 CSS を勉強して学んだのですが、CSS にはカウンタというものがあり、要素を数えること、また、その番号を表示していくことができます。

これによって何ができるようになるかというと、TeX や Word のように、図の番号の自動採番や章番号の自動付与なんかが CSS のみで可能になります。 これで、参照の解決とかまでやってくれればなお良いんですが…。

章番号の自動付与

ここではまず、章番号を自動的に付与してくれるようにしてみます。完成イメージは以下のようになります。

<h1>Section A<h1>
<h2>SubSection a</h2>
<h3>SubSubSection a</h3>
<h3>SubSubSection b</h3>
<h2>SubSection b</h2>
<h1>Section B</h1>
<h2>SubSection c</h2>
<h3>SubSubSection c</h3>
<h3>SubSection d</h3>

f:id:kiririmode:20180626154639p:plain:w200

CSS におけるカウンター定義

最初に、カウンターを宣言・初期化します。宣言・初期化は、counter-reset で行います。

はてなブログのエントリ本文は entry-content クラスでマークされるので、そのエントリ本文開始時に section (h1 タグに相当)、subsection (h2 タグに相当)、subsubsection (h3 タグに相当) という 3 つのカウンタを定義します。規定値は 0 ですが、これは CSS で変更することが可能です。

h1 タグが出現したらその下位にあたる 2 つのカウンタを初期化、h2 タグが出現したら、その下位にあたるカウンタを初期化すれば良いですね。

.entry-content {
    counter-reset: section subsection subsubsection;
}

.entry-content h1 {
    counter-reset: subsection subsubsection;
}

.entry-content h2 {
    counter-reset: subsubsection;
}

カウンタのインクリメントと出力

各カウンタに対応する h[1-3] タグが出現したときに、その値をインクリメントします。 また、そのタグが出現したときは、章番号を出力できるときなので、その表示も同時にしてしまいましょう。

特定のタグが出現したとき別の何かを表示するのは、疑似要素(Pseudo-Element) を使用することで可能です。 ここでは、::before 疑似要素を使用します。

.entry-content h1::before {
    counter-increment: section;
    content: counter(section) ". ";
    letter-spacing: 1px;
}

.entry-content h2::before {
    counter-increment: subsection;
    content: counter(section) "." counter(subsection) ". ";
    font-size: 1.5rem;
    letter-spacing: 1px;
}

.entry-content h3::before {
    counter-increment: subsubsection;
    content: counter(section) "." counter(subsection) "." counter(subsubsection) ". ";
    font-size: 1.2rem;
    letter-spacing: 1px;
}

counter-increment がその名の通りカウンタ値を +1 し、content が要素の表示です。 カウンタ値の参照は counter([counter-name]) で行います。

実は既にこの Blog (ただしPC用のみ)には当該の CSS を適用しているので、だいたい表示イメージはお分かりかと思います。

目次にも章番号を付与する

はてなブログには [:contents] と書くと目次を自動生成してくれるという機能があります。章見出しだけでなく、この目次にも章番号を振りたい。

この見出しは ul.table-of-contents でレンダリングされるので、ここでカウンタを初期化すれば良いです。

ul {
    counter-reset: toc;
}

.table-of-contents li::before {
    counter-increment: toc;
    content: counters(toc, ".") ". ";
    letter-spacing: 1px;
}

ここではちょっとしたテクニックを使っていて、content でカウンタ値を参照するとき、counter ではなく counters を 使っています。

この理由についてですが、まず前提としてはてなブログの「目次」は ul タグの入れ子で構成されています。 そのため、ul タグに対して counter-reset を行うようにしておくと、入れ子におけるそれぞれのレベルの ul タグについて、 カウンタが定義されるようになります。

そのような複数のカウンタを counters は順に全て参照することができます。 そのため、多階層の章番号 (3.2. とか 1.2.1 とか) をごく僅かな記述で生成することができるようになります。

このエントリの見出しは以下のようになります。

参考