の番号だけ装飾するには?CSSカウンタを使ってみた

順序リストの表示に利用するol要素。
デフォルトではごくシンプルな番号つきリストですが、デザイナーさんからこんな風に番号部分だけ色を変えるなどの装飾がされたデザインを渡されたらどのようにCSSを作りますか?

数字部分だけに装飾があるデザインの順序リスト

…簡単そうに見えて、意外と悩むのではないでしょうか?
今回の記事では、こんなシーンで使えるCSSのTipsをご紹介します。

最初からついている数字は使わない

結論から言うと、list-style-typeによって付与される数字は使いません。
ここだけを装飾する方法はないので、せっかくですが指定自体を無くすことになります。

ol{
  list-style-type: none;
}

ここから活躍するのが当記事の主役、CSS2から登場した「カウンタ機能」です。
これを使って1,2,3,4…といった連番を疑似要素:beforeにつけなおす方法をとった上で、自由に装飾できるようにしてみましょう。

カウンタを使ってみよう

それでは、カウンタの使い方を解説していきます。まずは最終完成系のご紹介です。
今回は入れ子にしたリストも別途採番していく想定でサンプルを作りました。

デモ

  1. 親リスト1です サンプルテキストサンプルテキスト
    1. 子リスト1です サンプルテキストサンプルテキスト
      1. 孫リスト1です サンプルテキストサンプルテキストサンプルテキストサンプルテキスト
        サンプルテキストサンプルテキストサンプルテキストサンプルテキスト
      2. 孫リスト2です
      3. 孫リスト3です
    2. 子リスト2です
    3. 子リスト2です
  2. 親リスト2です
  3. 親リスト3です

サンプルコード全体:HTML

HTMLは、普通に順序つきリストを作ってあげればOKです。

<ol>
  <li>親リスト1です サンプルテキストサンプルテキスト
    <ol>
      <li>子リスト1です サンプルテキストサンプルテキスト
        <ol>
          <li>孫リスト1です サンプルテキストサンプルテキスト
           <br>サンプルテキストサンプルテキストサンプルテキスト</li>
          <li>孫リスト2です</li>
          <li>孫リスト3です</li>
        </ol>
      </li>
      <li>子リスト2です</li>
      <li>子リスト2です</li>
    </ol>
  </li>
  <li>親リスト2です</li>
  <li>親リスト3です</li>
</ol>

サンプルコード全体:CSS

ol{
  counter-reset: item;
  list-style-type: none;
  padding-left: 0;
}
ol ol{
  padding-left: 1em;
}
li{
  text-indent: -1.3em;
  padding-left: 1.3em;
}
li:before {
  counter-increment: item;
  content: counter(item)'.';
  /* 以下は自由に装飾... */
  padding-right: .5em;
  font-weight: bold;
  color: #b40000;
}

上記のCSSサンプルコードは余白調整などのスタイルももろもろ込みですが、ポイントはこの3つ。
ひとつずつ見ていきます。

  • counter-resetプロパティ
  • counter-incrementプロパティ
  • contentプロパティ内で指定するcounter関数

counter-resetプロパティ

counter-resetは名前のとおり、カウンタをリセットするためのプロパティです。

サンプルでの指定値「item」は変数のようなもので、任意に決めてOKです。この後のプロパティでも使うので適宜わかりやすい名前をつけてください。
また、変数に続けて整数を指定すると2以上の番号からカウントし始めることもできます。

/*指定パターン*/
ol{
  counter-reset: item;
  counter-reset: item 1; /*「2」からカウントし始める*/
}

これを適用した要素が出てくるたびに、カウンターがリセット(=1からスタート)されます。どの要素でカウンタをリセットしたいか?で記述位置を考えましょう。
記述位置を間違えたときこんなNG例が起こりがちです。

【NG例 1】すべて「1」になってしまう

すべて「1」

/*NG例*/
li{
  counter-reset:item;
}
li:before{
  counter-increment:item;
  content: counter(item)'.';
}

番号を振るのがliなのでlicounter-resetを設定したくなるかもしれませんが、これではliのたびにカウンタをリセットしていることになるのですべて「1」となってしまいます。

【NG例 2】子要素はカウンタをわけたいのに親要素から連番が続いてしまう

親要素から連番が続いてしまう

/*NG例*/
ol.parent{
  counter-reset:item; /* class="parent"の要素でしかカウンタがリセットされていない */
}
li:before{
  counter-increment:item;
  content: counter(item)'.';
}

親のolだけにclassをつけているとき、子のolcounter-resetの指定対象から外れてしまった…ということが起こりやすいです。
それぞれのolできちんとカウンタをリセットするような記述になっているか要チェックです。

counter-incrementプロパティ

counter-incrementカウンタの値を進めるプロパティです。これにより、番号が1ずつ進んでいきます。

どのカウンターが対象か、先ほど決めた変数を指定しましょう。
変数に続けて数字を指定すると「カウントをいくつずつ進めていくか」を変えられます。負数を入れればカウント値をマイナスしていくことも可能です。

/*指定パターン*/
li:before{
  counter-increment:item;
  counter-increment: item 2; /*カウントを2ずつ増やす 2,4,6,8...*/
}

これも、適用した要素が出てくるたびにカウンタの値が進むのでどの要素でカウンタを進めたいかで記述位置を考えてください。

counter関数

ここまでの設定に沿ってカウントした番号を出力するのが、counter関数。
疑似要素:beforecontentプロパティ内で実行します。

必須の指定は第1引数、対象カウンタの変数です。
第2引数にリストタイプ名を指定すると、出力される番号の種類を数字以外に変えることもできます。

/*指定パターン*/
li:before{
  content: counter(item);
  content: counter(item, {list-style-type}); /*指定したリストタイプで番号を出力*/
}

※リストタイプ名は、list-style-typeプロパティで使えるものなら何でもOKです。
例えばcounter(item, hiragana-iroha);と指定すれば、「1,2,3…」が「い,ろ,は…」に変わります。
参考:list-style-type-スタイルシートリファレンス

また、counter関数単体で出力されるのは番号だけなので、末尾に「.(ドット)」などを入れたい場合は関数の外に通常の文字列として入れてあげてください。

li:before{
  content: counter(item)'.'; /*番号末尾に「.」を出力*/
}

ここまでで基本の実装は完了です!
あとはli:beforeに対して、文字色でも背景でも、自由にスタイルをつけていきましょう。

行頭揃えに関する課題

1点課題を挙げるとすると、もし改行が発生した場合にこのように文頭がはみ出してしまいます。

テキストの行頭を揃えたい

これを解決するひとつの方法に、text-indentを使ったものがあります。
サンプルコードではliに記述している内容で、これでひとまずはきれいに表示されます。

li{
  text-indent: -1.3em;
  padding-left: 1.3em;
}

(「※」マークを疑似要素に入れて注釈リストを作りたいときなどにも覚えておきたい書き方です)

ただし本件の場合、実はこのように「n文字分動かす」という指定をしていると番号が2桁以上になったときに結局文頭がずれてしまうという課題が…。これを解決するにはひと手間かかりそうなので、またの機会にご紹介したいと思います。
「絶対10個もリスト項目並べない!大丈夫!」という自信があるとき(?)にはこれでよしとすることもできるので、簡単な手段として心に留めておいてもよいでしょう。


今回はここまで。CSSのカウンタ機能の使い方を中心に、olの番号部分だけを装飾できるようにする方法をご紹介してきました。

これを応用すればリストに限らず、ランキングのブロックを自動で採番したいときや、見出しに「第〇章」と採番していきたいときなどにも使えそうです。CSS2からあった機能ですが意外とこれまで使ったことがなかったので、同じような方の参考になれば幸いです!