CSSカウンタの真実:`ol`タグの呪縛から解き放たれる連番制御の極意
フロントエンドの現場で、「デザインの都合で`ol`や`li`が使えない」という壁にぶつかったことはありませんか?
「リスト構造ではないけれど、見た目上は連番を振りたい」。そんな時、安易にJavaScriptでDOMを操作して数字を埋め込もうとするのは、ちょっと待ってください。
その処理、CSSだけで完結させましょう。`counter-reset`と`counter-increment`。この二つのプロパティを使いこなせば、ブラウザのレンダリングエンジンを味方につけ、セマンティクスを損なうことなく、極めてスマートに連番を制御できます。
今日は、中級エンジニアの皆さんが明日から現場で自信を持って使える、CSSカウンタの「本質」と「実装パターン」を伝授します。
—
1. CSSカウンタが裏側でやっていること
CSSカウンタは、ブラウザが内部で保持する「変数」のようなものです。仕組みはシンプルですが、以下の3つのステップで成り立っています。
1. `counter-reset`: カウンタの初期化。変数を宣言し、開始値をセットする。
2. `counter-increment`: カウンタの加算。対象の要素が出現するたびに値を増やす。
3. `counter()`関数: 実際に値を表示する。`::before`や`::after`の`content`プロパティ内で呼び出す。
重要なのは、これが「レンダリングツリー」上でのみ完結する処理だということ。DOM構造を書き換えないため、アクセシビリティやスクレイピング耐性が高く、何よりJavaScriptのイベントループを汚さないのが最大のメリットです。
—
2. 実践的サンプル:柔軟なセクション番号付け
実務でよく遭遇する「セクションタイトルに連番を振る」ケースを例に見ていきましょう。ここでは、親要素に`counter-reset`を置き、子要素である見出しで`counter-increment`を回すという、CSS設計の王道パターンを採用します。
/ カウンタの初期化:親コンテナで定義するのが鉄則 /
.article-container {
counter-reset: section-counter; / ‘section-counter’という名前の変数を0で初期化 /
}
/ 見出しに連番を適用 /
.section-title {
counter-increment: section-counter; / 出現するたびに値を1ずつ増やす /
}
/ 擬似要素を使って数字を表示 /
.section-title::before {
content: “第” counter(section-counter) “章:”;
margin-right: 0.5em;
font-weight: bold;
color: #0070f3;
}
導入:CSSカウンタの基礎
実践:ブラウザの挙動を理解する
応用:ネストされた連番の制御
—
3. なぜ「中級者」はここを意識すべきなのか?
この技術の真価は、「ネストされた構造」でこそ発揮されます。
例えば、「1.1」「1.2」のような階層構造を持つ連番を作りたい場合、`counter-reset`のスコープを理解していないと沼にはまります。
ネストされたカウンタの実装例
.chapter-list {
counter-reset: chapter; / 親階層のカウンタ /
}
.chapter-item {
counter-increment: chapter;
}
.chapter-item::before {
content: counter(chapter) “. “;
}
/ サブアイテムの制御 /
.sub-list {
counter-reset: sub-chapter; / 子階層のカウンタをここでリセット /
}
.sub-item {
counter-increment: sub-chapter;
}
.sub-item::before {
/ 親と子のカウンタを連結して表示 /
content: counter(chapter) “-” counter(sub-chapter) ” “;
}
このコードのポイントは、`.sub-list`で`counter-reset`を行っている点です。これにより、親の`chapter`の値は保持したまま、`sub-chapter`だけをゼロからカウントアップできます。この挙動を知っていれば、複雑なドキュメントUIも怖くありません。
—
4. プロとして気をつけておくべき注意点
最後に、シニア視点からの「現場の知恵」を共有します。
- display: noneに注意: `display: none`が指定された要素は、CSSカウンタのカウント対象から除外されます。もし「非表示の要素も含めてカウントしたい」という特殊な要件がある場合は、`visibility: hidden`や`opacity: 0`で制御する必要があります。
- 柔軟なフォーマット: `counter(name, list-style-type)`のように、第二引数に`upper-roman`や`lower-alpha`などを指定可能です。これを使うと、わざわざ画像を用意しなくても、お洒落なリスト番号が即座に作れます。
- やりすぎない: 何でもCSSカウンタで解決しようとすると、後からコードを見たメンバーが「数字がどこから湧いてきているのか分からない」という状態に陥ります。あくまで「DOM構造と連番の表示が密接に関連している時」に限定して使うのが、持続可能なコードベースを保つコツです。
CSSは単なるスタイリング言語ではありません。ブラウザという高機能なエンジンを操るための「命令セット」です。ぜひ、このカウンタ機能を使いこなし、DOMを汚さない美しいマークアップを追求してください。
現場からは以上です。また次のTipsでお会いしましょう。

コメント