はじめに
Web制作の現場において、リストの番号付けや見出しの階層管理は日常的なタスクです。多くの開発者は、HTMLのolタグやliタグの標準的なリスト機能に頼るか、あるいはJavaScriptを用いて動的に数値を生成する方法を選択します。しかし、CSSには古くから実装されながら、現代のモダンなWebデザインにおいても非常に強力なツールとして機能する「CSS Counters」が存在します。特にcounter-resetプロパティを軸とした実装は、DOM構造を汚染することなく、純粋なCSSだけで柔軟な番号管理を実現できるため、パフォーマンスと保守性の観点から非常に有用です。本稿では、シニアWebデザイナーの視点から、counter-resetを用いた実務的な実装手法と、陥りやすい罠、そして応用テクニックについて深掘りします。
CSS Countersの基本概念と3つのプロパティ
CSS Countersを制御するためには、以下の3つのプロパティを理解する必要があります。
1. counter-reset: カウンターを初期化、またはリセットする。
2. counter-increment: カウンターの値を加算する。
3. counter(name) または counters(name, string): カウンターの現在値を表示する。
counter-resetは、指定した名前のカウンターを特定の数値(デフォルトは0)にリセットします。このプロパティを親要素に付与することで、その子要素内でのカウントを開始する準備が整います。
実務での基本実装:カスタムリストの作成
標準のolタグはスタイル調整に制限があることが多いです。デザインカンプ通りの複雑な番号付きリストを実装する場合、ulタグと擬似要素を組み合わせる手法が定石です。
コード例:
.list-container {
counter-reset: custom-counter 0;
}
.list-item {
display: flex;
align-items: center;
}
.list-item::before {
counter-increment: custom-counter 1;
content: “0” counter(custom-counter);
margin-right: 10px;
font-weight: bold;
color: #333;
}
このコードでは、親要素でカウンターを初期化し、各アイテムの擬似要素でインクリメントと表示を行っています。このようにすることで、マークアップを変えずに番号の装飾を自由に行うことが可能です。
ネストされたリストの管理:counters()関数の活用
実務において最も真価を発揮するのは、多階層のリスト管理です。たとえば、マニュアルの章立てや、複雑な構造を持つドキュメントページなどです。単一のcounter()関数では階層ごとの数値を保持できませんが、counters()関数を使うことで「1.1」「1.1.2」といった階層的な番号表示を自動化できます。
コード例:
.section-wrapper {
counter-reset: section;
}
.section-title {
counter-increment: section;
}
.section-title::before {
content: counters(section, “.”) “. “;
}
このように記述することで、DOMが深くネストされていても、CSSだけで自動的に親の番号を引き継いだ親子関係の番号付けが可能になります。JavaScriptでDOMを走査して番号を振る手法と比較して、再レンダリングコストが発生しないため、大規模なドキュメントサイトでは極めて有効な手法です。
応用編:逆順カウントと特定の数値からの開始
counter-resetは、単に0にリセットするだけでなく、初期値を指定することも可能です。例えば、記事の後半からカウントを始めたい場合や、特定の数値から開始したい要件にも対応できます。
.custom-start {
counter-reset: my-counter 10; / 10からカウントを開始 /
}
また、counter-incrementに負の値を指定することで、逆順のカウントも実現できます。
.reverse-list {
counter-reset: reverse-count 10;
}
.reverse-item {
counter-increment: reverse-count -1;
}
.reverse-item::before {
content: counter(reverse-count);
}
このテクニックは、カウントダウンタイマー風のUIや、特定のセクション内での逆順表示が必要なデザインにおいて、非常にスマートな解決策となります。
実務で注意すべきポイントとベストプラクティス
1. 可読性の維持
counter-resetの名前は、スコープを明確にするために、意味のある名称(例:step-counter, chapter-index)を付けるようにしましょう。グローバルな名前空間を汚染しないよう、コンポーネント単位で管理するのがベストです。
2. 擬似要素の制約
CSS Countersは、あくまで擬似要素(::beforeや::after)のcontentプロパティで表示します。そのため、番号に対して複雑なレイアウト(番号自体にさらにアイコンを配置する、ホバー時にアニメーションさせる等)を適用する場合、擬似要素のdisplayプロパティやpositioningを駆使する必要があります。
3. アクセシビリティへの配慮
ここが最も重要な点ですが、CSS Countersで生成された数値は、スクリーンリーダーによって読み上げられない場合があります。視覚的な装飾として割り切るなら問題ありませんが、文書構造として重要な番号である場合は、隠しテキストとしてaria-labelを付与するか、あるいはHTMLのセマンティクスを優先することを検討してください。実務では、デザイン上の装飾としての番号付けにCSS Countersを使用し、意味のある構造にはHTMLのol/liを基本とするのが、プロフェッショナルな設計思想です。
4. ブラウザ互換性
現在、主要なモダンブラウザはすべてCSS Countersをサポートしています。古いIE環境などを考慮する必要がある場合でも、CSS Counters自体はエラーを吐くことは少なく、単に表示されないという挙動になるため、プログレッシブ・エンハンスメントの考え方に基づき、フォールバックを考慮した実装が可能です。
パフォーマンスの観点から
CSS Countersは、ブラウザのレンダリングエンジン内で最適化されており、JavaScriptによるDOM操作よりも圧倒的に高速です。特に、数千行に及ぶリストや、頻繁に表示・非表示が切り替わるコンテンツにおいて、JavaScriptでの数値更新はレイアウトシフトやメモリリークの原因になることがあります。CSSによる管理は、これらの懸念を払拭し、ブラウザの描画性能を最大限に引き出すことができます。
結論
CSSのcounter-resetは、単なる「番号をリセットする機能」ではありません。これは、WebデザイナーがHTMLの構造に依存しすぎることなく、デザインの意図を正確にブラウザ上で再現するための強力な論理エンジンです。ネストされたリストの管理、逆順カウント、そしてパフォーマンスの最適化まで、その応用範囲は多岐にわたります。
実務においては、常に「この番号付けは文書構造として必須か、それともデザイン上の演出か」を自問自答してください。演出であればCSS Countersを採用し、HTMLをクリーンに保つ。この判断こそが、保守性の高いコードを書くシニアデザイナーの仕事です。ぜひ、次回のプロジェクトでこの強力な機能を積極的に取り入れ、CSSだけで完結するエレガントな実装を体感してください。

コメント