シリーズ「CSS セレクタのレシピ」では、CSS セレクタのテクニックを紹介していきます。

CSS は開発のサイクルを活発にするために、モジュール単位で仕様が策定されています。セレクタに関しては、現時点では 2018 年 11 月に勧告(Recommendation)された「Selectors Level 3」がスタンダードですが、Working Draft の「Selectors Level 4」のいくつかの機能も、主要ブラウザではすでにサポートされています。

この記事では、:nth-child():nth-last-child() のように、擬似クラスに -child が付く「子要素インデックス1」の、「Selectors Level 4」まで含めた CSS セレクタのテクニックとその仕組みを説明してきます。

  • 紹介するセレクタには複雑な記法を含みますが、直感的に理解できないセレクタはメンテナンス性を損なうので、他に手段がない場合にのみ限定的に使うようにしましょう。
  • 加えて、役割がわかるようにコードにコメントを残しておくとよいかもしれません。

この記事のサンプルの見た目と、ベースとなる HTML コードは以下です。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
サンプルで使用する HTML
<ul>
  <li class="item">1</li>
  <li class="item">2</li>
  <li class="item">3</li>
  <!-- ... -->
</ul>

この HTML の、最初のリスト項目(.item)にスタイルを加えると、以下の見た目になります。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
最初の要素にスタイルを指定する CSS
.item:first-child { 
  /* スタイルの指定 */
}

それでは、これらのフォーマットをもとに、CSS セレクタのレシピを紹介していきます。

以下は、.item の最初から 3 番目までの要素にスタイルを指定する例です。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
最初から 3 番目までにスタイルを指定する CSS
.item:nth-child(-n+3) { /* ... */ }

n には 0 から始まる整数が入るので、-0 + 3 = 3-1 + 3 = 2-2 + 3 = 1 となり、3 番目から最初の要素までが対象となります。

`:nth-child(-n+3)` の指定により、最初から 3 番目までの要素が対象となることを説明した図
:nth-child(-n+3)n には 0 から順番に整数が入る

以下は、.item の最後から 3 番目までの要素にスタイルを指定する例です。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
最後から 3 番目までにスタイルを指定する CSS
.item:nth-last-child(-n+3) { /* ... */ }

こちらは前述の「最初から n 番目まで」の応用で、:nth-last-child() 擬似クラスを使用することで、後方から参照しています。

`:nth-last-child(-n+3)` の指定により、最後から 3 番目までの要素が対象となることを説明した図
:nth-last-child(-n+3)n には 0 から順番に整数が入る

以下は、.item の 4 番目から最後までの要素にスタイルを指定する例です。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
4 番目から最後までにスタイルを指定する CSS
.item:nth-child(n+4) { /* ... */ }

n には 0 から始まる整数が入るので、0 + 4 = 41 + 4 = 52 + 4 = 6 … と続いていくため、4 番目から最後までの要素が対象となります。

また、最初の子要素以外にマージンを付けるケースがよくありますが、そのときに :nth-child(n+2) が使用できます。

最初の子要素以外にマージンを指定する CSS
.item:nth-child(n+2) {
  margin-top: 40px;
}

/* `:not()` 擬似クラスでも同様の実装が可能 */
.item:not(:first-child) {
  margin-top: 40px;
}

以下は、.item の後ろから数えて 4 番目から最初までの要素にスタイルを指定する例です。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
後ろから数えて 4 番目から最初までにスタイルを指定する CSS
.item:nth-last-child(n+4) { /* ... */ }

こちらは前述の「n 番目から最後まで」の応用で、:nth-last-child() 擬似クラスを使用することで、後方から参照しています。

また、最後の子要素以外にマージンを指定するときに :nth-last-child(n+2) が使用できます。

最後の子要素以外にマージンを指定する CSS
.item:nth-last-child(n+2) {
  margin-bottom: 40px;
}

/* `:not()` 擬似クラスでも同様の実装が可能 */
.item:not(:last-child) {
  margin-bottom: 40px;
}

以下は、.item の 4 番目から 7 番目までの要素にスタイルを指定する例です。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
4 番目から 7 番目までにスタイルを指定する CSS
.item:nth-child(n+4):nth-child(-n+7) { /* ... */ }

こちらは「n 番目から最後まで」と「最初から n 番目まで」を組み合わせた記法です。

`:nth-child(n+4)` と `:nth-child(-n+7)` の指定により、4 番目から 7 番目までの要素が対象となることを説明した図
:nth-child(n+4):nth-child(-n+7) の両方の条件を満たす要素が対象となる

以下は、.item の要素数が 5 のときにスタイルを指定する例です。
1 番目のサンプルは要素数が 4 のため、スタイルが適用されません。

  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4
  • 5
要素数が 5 のときにスタイルを指定する CSS
.item:first-child:nth-last-child(5),
.item:first-child:nth-last-child(5) ~ .item { /* ... */ }

この記法では、まず、:first-child(最初の要素)と :nth-last-child(5)(最後から 5 番目の要素)が同一であることが条件となります。

`:first-child` で指定している要素と、`:nth-last-child(5)` で指定している要素が一致していることを説明した図
:first-child:nth-last-child(5) で指定している要素が一致する

また、セレクタが , (カンマ)でリスト化され、重複した指定になるので冗長に感じますが、それぞれ以下の役割を担っています。

  • 1 行目: .item:first-child:nth-last-child(5) は、最初の要素を選択
  • 2 行目: .item:first-child:nth-last-child(5) ~ .item は、~(チルダ)で接合することで、最初の要素を除いた 2 番目以降の要素を選択

これらの指定の組み合わせにより、要素数が 5 のときにのみ、すべての要素にスタイルを適用することができます。

以下は、.item の要素数が 5 以上のときにスタイルを指定する例です。
1 番目のサンプルは要素数が 4 のため、スタイルが適用されません。

  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4
  • 5
要素数が 5 以上のときにスタイルを指定する CSS
.item:first-child:nth-last-child(n+5),
.item:first-child:nth-last-child(n+5) ~ .item { /* ... */ }

こちらは前述の「要素数が n と一致」の応用で、(n+5) とすることで、要素数が 5 以上のときに対象となります。

以下は、.item の要素数が 5 以下のときにスタイルを指定する例です。
1 番目のサンプルは要素数が 6 のため、スタイルが適用されません。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
要素数が 5 以下のときにスタイルを指定する CSS
.item:first-child:nth-last-child(-n+5),
.item:first-child:nth-last-child(-n+5) ~ .item { /* ... */ }

こちらも「要素数が n と一致」の応用で、(-n+5) とすることで、要素数が 5 以下のときに対象となります。

要素数が n 以上 n 以下

見出し「要素数が n 以上 n 以下」

以下は、.item の要素数が 5 以上 7 以下のときにスタイルを指定する例です。
1 番目、2 番目のサンプルは要素数がこの範囲に収まらないため、スタイルが適用されません。

  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
要素数が 5 以上 7 以下のときにスタイルを指定する CSS
.item:first-child:nth-last-child(n+5):nth-last-child(-n+7),
.item:first-child:nth-last-child(n+5):nth-last-child(-n+7) ~ .item { /* ... */ }

こちらは「要素数が n 以上」と「要素数が n 以下」を組み合わせた記法です。
セレクタが複雑になり、直感的ではないため、むやみに使うのは避けた方がよいでしょう。

以下は、.item の要素数が奇数のときにスタイルを指定する例です。
1 番目のサンプルは要素数が偶数のため、スタイルが適用されません。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
要素数が奇数のときにスタイルを指定する CSS
.item:first-child:nth-last-child(2n+1),
.item:first-child:nth-last-child(2n+1) ~ .item { /* ... */ }

「要素数が n と一致」の応用で、(2n+1) とすることで、要素数が奇数のときに対象となります。

以下は、.item の要素数が偶数のときにスタイルを指定する例です。
1 番目のサンプルは要素数が奇数のため、スタイルが適用されません。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
要素数が偶数のときにスタイルを指定する CSS
.item:first-child:nth-last-child(2n),
.item:first-child:nth-last-child(2n) ~ .item { /* ... */ }

「要素数が n と一致」の応用で、(2n) とすることで、要素数が偶数のときに対象となります。

特定の属性値の n 番目

見出し「特定の属性値の n 番目」

以下は、特定の属性値の n 番目にスタイルを指定する例です。
このサンプルでは以下のように、要素ごとに abc のクラスを付与しています。

サンプルで使用する HTML
<ul>
  <li class="item a">A</li>
  <li class="item b">B</li>
  <li class="item c">C</li>
  <!-- ... -->
</ul>

このとき、.a を持つ 3 番目の要素にスタイルを指定するには、以下のコードで実現できます。

  • A
  • B
  • C
  • A
  • B
  • C
  • A
  • B
  • C
  • A
特定の属性値の 3 番目にスタイルを指定する CSS
:nth-child(3 of .a) { /* ... */ }

このように、:nth-child() 擬似クラスで of S を使うことで2、特定の属性値が付与された要素の n 番目を指定することができます。

`:nth-child(3 of .a)` の指定により、3 番目に出現する `.a` が対象となることを説明した図
:nth-child(3 of .a) で、3 番目に出現する .a が対象となる

なお、この of S を使用した Selectors Level 4 の記法は、現時点では主要ブラウザのなかで Firefox が非対応ですが、次期バージョンの 113 よりサポートされる予定です3

フィルタに対応したストライプ

見出し「フィルタに対応したストライプ」

以下は :nth-child(even) で、偶数番目の要素のみにストライプのスタイルを付けた例ですが、フィルタ機能によって一方の要素を hidden 属性によって非表示にすると、ストライプのパターンが変わってしまいます。

  • A
  • B
  • A
  • A
  • A
  • B
  • B
  • B
  • A
  • A
偶数にスタイルを指定する CSS
.item:nth-child(even) { /* ... */ }

この問題を解消するには、フィルタ実行時に JS で調整する方法が考えられますが、:nth-child(even of :not([hidden])) の記法により、CSS のみで実現することができます。

  • A
  • B
  • A
  • A
  • A
  • B
  • B
  • B
  • A
  • A
動的なフィルタに対応した、偶数にスタイルを指定する CSS
.item:nth-child(even of :not([hidden])) { /* ... */ }

例えば、フィルタの選択を「A」にすると、「B」に hidden 属性が付与されますが、:nth-child(even of :not([hidden])) によって、hidden 属性が指定された要素以外の偶数番目(even)の要素を対象とすることができます。

`:nth-child(even of :not([hidden]))` の指定により `hidden` 属性が指定された要素を除いた偶数番目の要素が対象となることを説明した図
hidden 属性が指定された要素を除いた偶数番目の要素が対象となる

このテクニックは、ゼブラストライプ(zebra striping)と呼ばれる、表組み(table 要素)の行に対して交互に色を指定したときに、フィルタ機能を付与したケースで特に有効です。

No. カテゴリ
1 Apple
2 Banana
3 Apple
4 Apple
5 Apple
6 Banana
7 Banana
8 Banana
9 Apple
10 Apple

また、それ以外のケースとして、記事ページの最後に関連する記事一覧を表示するときに、見ているページの記事(自分自身)を非表示にするコードを書くことがありますが、その場合にも使うことができそうです。

なお、こちらも of S を使用した Selectors Level 4 の記法なので、現時点では主要ブラウザのなかで Firefox が非対応ですが、次期バージョンの 113 よりサポートされる予定です3

本記事の作成にあたり、以下のウェブページや書籍を参考にしました。

脚注

  1. W3C 仕様書における「Selectors Level 4」の「Child-indexed Pseudo-classes」に該当しますが、本記事では簡略化した「子要素インデックス」の表記を用います。

  2. of SS はセレクタリスト(selector list)です。,(カンマ)区切りで複数のセレクタを指定することができます。

  3. selector list argument of :nth-child and :nth-last-child CSS pseudo-classes | Can I use… 2