CSS3では:first-childや:nth-child、:not()のような擬似クラスで柔軟にセレクタを指定することができます。OOCSSのようなある種のデザインパターンでも、シングルクラスでコンテンツに依存する書き方の場合でも活用することができると思います。
サンプルはCodepenにまとめています。照らし合わせながら読んでいくと理解しやすいです。
See the Pen pseudo-class-test by ManabuYasuda (@gaku) on CodePen.
HTMLは以下のようにしています。.sectionという親要素に.section__itemという子要素が8つ入っています。最初の2つのサンプルには見出しが、後半のサンプルではクラス名を変えていたり、子要素の数を7つにしているものもあります。
<div class="section section1">
<h3>:first-child</h3>
<div class="section__item">1</div>
<div class="section__item">2</div>
<div class="section__item">3</div>
<div class="section__item">4</div>
<div class="section__item">5</div>
<div class="section__item">6</div>
<div class="section__item">7</div>
<div class="section__item">8</div>
</div>
childは使わない
擬似クラスには:first-childと:first-of-typeのように微妙に違うセレクタがあります。結論から言うと、-of-typeを使う方がベターです。
.section1 .section__item:first-child {
background-color: teal;
}
<div class="section section1">
<h3>:first-child</h3>
<div class="section__item">1</div>
<div class="section__item">2</div>
<div class="section__item">3</div>
<div class="section__item">4</div>
<div class="section__item">5</div>
<div class="section__item">6</div>
<div class="section__item">7</div>
<div class="section__item">8</div>
</div>
例えば上記のように:first-childで指定した場合、直近の子要素にセレクタで指定しているもの以外の要素があると、期待どおりにならないことがあります。
:first-childは親要素から見た子要素を要素のタイプに関係なく数えるので.section__itemより上にあるh3要素も数に入ってしまっています。つまり、この場合は.section1の1番目の子要素を探し、かつ.section__itemであれば適応されます。1番目の要素はh3で、さらに.section__itemでもないので適応されないということです。
これを解決する方法は:first-of-typeで指定すること。:first-childと違ってクラス名を判別してくれるので、間違いが起こりにくです。
.section2 .section__item:first-of-type {
background-color: teal;
}
最後の要素を指定する
:last-of-typeを指定します。
.section3 .section__item:last-of-type {
background-color: teal;
}
x番目の要素を指定する
:nth-of-type(x)を指定します。
.section4 .section__item:nth-of-type(2) {
background-color: teal;
}
奇数の要素を指定する
:nth-of-type(odd)もしくは:nth-of-type(2n+1)で指定します。
.section5 .section__item:nth-of-type(odd) {
background-color: teal;
}
:nth-of-type(2n+1)は(2×0)+1=1、(2×1)+1=3、 (2×2)+1=5のように計算されるので奇数に適応されます。
偶数の要素を指定する
:nth-of-type(even)もしくは:nth-of-type(2n)を指定します。
.section7 .section__item:nth-of-type(even) {
background-color: teal;
}
:nth-of-type(2n)は(2×0)+0=0、(2×1)+0=2、 (2×2)+0=4のように計算されます。
最初のx番目の要素を指定する
:nth-of-type(-n+3)のように指定すると、最初から3番目までの要素を指定できます。
.section8 .section__item:nth-of-type(-n+3) {
background-color: teal;
}
-0+3=3、-1+3=2、-2+3=1のように計算されます。nが正の整数だとプラス側に進み、負の整数だとマイナス側に進みます。
最初の要素以外を指定する
:nth-of-type(n+2)のように指定すると、最初の要素以外を指定できます。
.section9 .section__item:nth-of-type(n+2) {
background-color: teal;
}
0+2=2、1+2=3、2+2=4のように計算されます。
:not(:first-of-type)で指定すると同じ結果が得られます。こちらの方が何をしているのかが想像しやすいですね。
.section11 .section__item:not(:first-of-type) {
background-color: teal;
}
最後から数えてx番目の要素を指定する
:nth-last-of-type(2)のように指定すると、最後から2番目の要素を指定できます。
.section12 .section__item:nth-last-of-type(2) {
background-color: teal;
}
最後の要素でなおかつ奇数の要素を指定する
少しトリッキーですが、:nth-of-type(odd):last-of-typeのように指定すると、最後の要素と奇数の要素の両方が合致した要素を指定できます。
.section13 .section__item:nth-of-type(odd):last-of-type {
background-color: teal;
width: 25%;
}
例えば50%指定で横並びにしていて、奇数だと1つだけ残ってしまうので何かしらのスタイルをつけたい場合などに使えます。
最初と最後の子要素を指定する
親要素のマージンより子要素のマージンの方が大きいと、意図しない余白になってしまう場合があります。
> :first-childや> :last-childのように指定すると、最初の子要素や最後の子要素を指定することができます。
.section14 > :first-child {
background-color: teal;
margin-top: 0;
}
.section14 > :last-child {
background-color: lightgreen;
margin-bottom: 0;
}
>で直近の子要素を指定できます。クラス名などを指定する必要がないので汎用的に使えます。
あるクラス名で始まるx番目の要素を指定する
[class=""]のような属性セレクタと組み合わせると部分的に一致する要素を指定することもできます。
例えば子要素をsection__item1やsection__item2のようにクラス名をつけている場合、
<div class="section section15">
<div class="section__item1">1</div>
<div class="section__item2">2</div>
<div class="section__item3">3</div>
<div class="section__item4">4</div>
<div class="section__item5">5</div>
<div class="section__item6">6</div>
<div class="section__item7">7</div>
<div class="section__item8">8</div>
</div>
[class^="クラス名"]のように指定するとクラス名で始まる要素のx番目のように指定ができます。
.section15 > [class^="section__item"]:nth-child(2) {
background-color: teal;
}
[]は属性をあらわしているセレクタで、^を$にすると「指定した文字列で終わる」、*にすると「指定した文字列が含まれている」要素に適応されます。
擬似クラスについてはMDNで仕様を確認するのがいいでしょう。nth-childを理解するにはCSS-TRICKSの記事がおすすめです。