【疑似クラス】nth-childとnth-of-typeの違いを徹底検証!

JavaScript

フロントエンドエンジニアやコーダーが結構おざなりにしているnth-childnth-of-typeの違いを解説します。知人の中にも「必要になったら毎回ググってる」人が多く、あまりきちんと理解しきれてないことがよくあります。

今回の目的は、セレクタの指定でよく使うnth-childnth-of-typeの違いを把握して、今後ググらなくてもよいように整理しておくことです。

悩見坂 楓
悩見坂 楓

何番目かを指定するときにいつもnth-childかnth-of-typeか分からなくてググッちゃうんだよね

著者
著者

ポイントを整理しておきましょうね

nth-child、nth-of-typeとは?

CSSに限らずjQueryやJavaScriptでも利用するシーンが多いですね。「何番目の」という意味のセレクタです。

毎回毎回「あれ、どっちだったっけ」となってGoogle検索をかけることがあるのではないでしょうか。

「:nth-child(n)」とは子要素のn番目を指定する疑似クラスです。CSSやjQueryなどに頻出します。 「:nth-of-type(n)」と違うのは指定外の要素をカウントするかどうかです。

では、早速実際のサンプルコードと共にどのような挙動をするのか検証していきましょう。

nth-childとnth-of-typeの根本的な違い

次のように<div>の中に複数の<p>があった場合はどうなるでしょうか?
まずはp:nth-child(3)として3番目の要素の文字色を変えてみましょう。

<div class="child-test">
  <p>1番目</p>
  <p>2番目</p>
  <p>3番目</p>
  <p>4番目</p>
  <p>5番目</p>
  <p>6番目</p>
  <p>7番目</p>
</div>

<style>
.child-test p:nth-child(3) { /* ←ここで疑似クラスnth-childを指定 */
  color: #d90368;
}
</style>

1番目

2番目

3番目

4番目

5番目

6番目

7番目

3番目の<p>の文字色が変わりますね。実はこれ、:nth-child(3)の代わりに:nth-of-type(3)で指定しても同じ結果になります。

<div class="of-type-test">
  <p>1番目</p>
  <p>2番目</p>
  <p>3番目</p>
  <p>4番目</p>
  <p>5番目</p>
  <p>6番目</p>
  <p>7番目</p>
</div>

<style>
.of-type-test p:nth-of-type(3) { /* ←ここで疑似クラスnth-of-typeを指定 */
  color: #d90368;
}
</style>

1番目

2番目

3番目

4番目

5番目

6番目

7番目

この例では:nth-child(3):nth-of-type(3)に違いがないことが分かりました。

では、次のように<p>のグループの中に<div>を混ぜてみます。

<div class="child-test">
  <p>1番目</p>
  <div>2番目</div> <!-- ←2番目の<p>を<div>に変更しました -->
  <p>3番目</p>
  <p>4番目</p>
  <p>5番目</p>
  <p>6番目</p>
  <p>7番目</p>
</div>

<style>
.child-test p:nth-child(3) { /* ←セレクタの指定は3番目の<p>の(つもりの)ままです */
  color: #d90368;
}
</style>

1番目

2番目

3番目

4番目

5番目

6番目

7番目

あれ、3番目の<p>を指定しているのに実質2番目の<p>の文字の色が変わっちゃうう!?ってなりますよね。p:nth-of-type(3)はどうでしょうか?

<div class="of-type-test">
  <p>1番目</p>
  <div>2番目</div> <!-- ←2番目の<p>を<div>に変更しました -->
  <p>3番目</p>
  <p>4番目</p>
  <p>5番目</p>
  <p>6番目</p>
  <p>7番目</p>
</div>

<style>
.of-type-test p:nth-of-type(3) { /* ←セレクタの指定は3番目の<p>のままです */
  color: #d90368;
}
</style>

1番目

2番目

3番目

4番目

5番目

6番目

7番目

p:nth-of-type(3)の時は、4番目の要素(<div>を含む)の文字色が変わりましたね。3番目の<p><div>をカウントしないで)の文字色がちゃんと変わりました。

おそらく皆さんが混乱するのはここですね。3番目の<p>を指定したつもりが3番目の子要素だったり4番目の子要素だったりするので訳が分からなくなるんです。

ここできちんと整理しておきましょう。nth-childとnth-of-typeの言葉の意味をつかんでおけばすんなり理解することが出来ます。

:nth-child
childは子要素の意味。nthはn番目のなので「n番目の子要素」。この場合<p>か<div>かは関係ない。
:nth-of-type
typeは型の意味。型はタグの種類を示すので、「n番目の○○タグ」を指定する。この場合、タグの種類が考慮される。

このように単語の意味を考えれば何も難しいことはありません。

nth-childとnth-of-typeでハマりがちな例

3番目の<div>

ちょっと雰囲気を変えてCSSで指定するのではなく、jQueryを使って指定してみましょう。次のようなDOM構造があると仮定します。

<div class="child-test-2">
  <p>1番目の<p></p>
  <div>1番目の<div></div>
  <p>2番目の<p></p>
  <div>2番目の<div></div>
  <p>3番目の<p></p>
  <div>3番目の<div>←ここの背景を青にしたい</div>
  <p>4番目の<p></p>
  <div>4番目の<div></div>
  <p>5番目の<p></p>
  <div>5番目の<div></div>
  <p>6番目の小夜子<p></p>
</div>

これの3番目の<div>の背景色を変えたいときにdiv:nth-child(3)を指定しがちですが痛い目にあいます。

// 失敗例
$(function(){
  $('.child-test-2 div:nth-child(3)').css('backgroundColor', 'blue');
});

1番目の<p>

1番目の<div>

2番目の<p>

2番目の<div>

3番目の<p>

3番目の<div>←ここの背景を青にしたい

4番目の<p>

4番目の<div>

5番目の<p>

5番目の<div>

6番目の小夜子

あれ、効かない……ってなりますよね。ですが効かなくて当然なんです。先ほど説明したのでもうお分かりでしょうが、この場合は:nth-child(n)ではなく:nth-of-type(n)を使うんですね。

$(function(){
  $('.child-test-2 div:nth-of-type(3)').css('backgroundColor', 'blue');
});

1番目の<p>

1番目の<div>

2番目の<p>

2番目の<div>

3番目の<p>

3番目の<div>←ここの背景を青にしたい

4番目の<p>

4番目の<div>

5番目の<p>

5番目の<div>

6番目の小夜子

これで「3番目のdiv」の背景の色がちゃんと変わりました。

最後の<li>

:nth-child(n)に類似して、:last-childという疑似要素があるので一応おさえておきましょう。次のサンプルコードを例に進めます。今回は、<li>が入れ子になっている場合です。

<ul class="last-child-test">
  <li>1番目のli
    <ul>
      <li>1番目のliの中のli</li>
    </ul>
  </li>
  <li>2番目のli
    <ul>
      <li>2番目のliの中のli</li>
    </ul>
  </li>
  <li>3番目のli
    <ul>
      <li>3番目のliの中のli</li>
    </ul>
  </li>
  <li>4番目のli←ここの背景色を変えたい!!
    <ul>
      <li>4番目のliの中のli</li>
    </ul>
  </li>
</ul>

$('.last-child-test li:last-child')というセレクタの指定をしがちですね……もちろんうまく動作しません。

// 失敗例
<script>
$(function(){
  $('.last-child-test li:last-child').css('backgroundColor', 'blue');
});
</script>
  • 1番目のli
    • 1番目のliの中のli
  • 2番目のli
    • 2番目のliの中のli
  • 3番目のli
    • 3番目のliの中のli
  • 4番目のli
    • 4番目のliの中のli

あらら、予期していない<li>まで背景が青くなってしまいましたね。理由は<li>の中に入れ子になっている<li>にも反応してしまうようなセレクタ指定が良くないからです。

$('.last-child-test li:last-child')という書き方では、深い階層にある余計な<li>にまで反応してしまいます。この場合の回避策は「>(大なり)」を間に挟んであげて、「(要素の)直下の」という指定をしてあげなくてはなりません。直下の<li>以外にも反応してしまうので、直下の要素のみに当てる感じです。

$('.last-child-test > li:last-child')というような具合ですね。するとうまく最後の1階層目の<li>の最後だけ背景色が変わるようになります。デザイン的な問題は置いておいて……

  • 1番目のli
    • 1番目のliの中のli
  • 2番目のli
    • 2番目のliの中のli
  • 3番目のli
    • 3番目のliの中のli
  • 4番目のli
    • 4番目のliの中のli

Chromeのデベロッパーツールで見てみましょう。きちんと(1階層目の)最後の<li>style=""が付与されているのが分かります。

特に何も考えずにjQueryで検証しましたが、CSSより分かりやすいかもしれませんね。class付けるとかstyle付けるとか、ぱっと見で分かるので視認性がよいです。

:first-child、:first-of-type、:last-child、last-of-typeも根本的な違いは:nth-child(n)、:nth-of-type(n)と同じ

まとめになりますが、以下の3点に気を付ければもうググらなくてよくなります。

  • childは子要素の意味で、どんな種類のタグでも無視して子要素の全部の中からN番目を指定する。
  • 反対にof-typeは型の意味で、指定したタグがN番目に登場した際に反応する。
  • <li>や<div>の入れ子は要注意。「>(直下)」をうまく利用して対象を絞り込む。

施行を整理すれば怖いものなどほとんどありません。どんな勉強方法でも施行を整理することや、間違えた内容を反復して思い出したり、書いたりすると自然とコーディング出来るようになりますね。

では、みなさんもハマらないように要点は押さえておいてくださいね!

タイトルとURLをコピーしました