こんにちは。いっとくです!
都内でWebのエンジニアをやっています。
普段はPHPを使っている時間が圧倒的に長いのですが、僕がいる現場ではフロントとバックで分業していないので、フロント部分を触ることも頻繁にあります。
でもフロントに関しては、「まぁ、、、作れるよ?」程度のレベルで、全く博士クラスまで達していないので、たまにドツボにはまることがあります。
そして、この前わけがわからなくなったのがnth-childやnth-of-typeのセレクタを使って、CSSを切り替えようとした時のこと。
特定のクラス名の要素に対して、交互に別のCSSを当てたかったのになんかうまくいかないじゃないか…
そこでnth-childとnth-of-typeの挙動について調べて知ったことを、徹底的に検証して安心していこうという記事でございます!
結論だけ知りたいという方は、一番下にまとめてあるので、そちらまで飛ばしちゃってください!
nth-childとnth-of-typeの挙動に関する実験
というわけでやっていく前に、MDNのドキュメントにある説明文を引用。
まずは、nth-child
CSS の :nth-child() 疑似クラスは、兄弟要素のグループの中での位置に基づいて選択します。
MDN web docs
なるほど。
つまり、兄弟要素の中で位置を指定しているけど、要素の種類は関係なさそう
続いて、nth-of-type
CSS の :nth-of-type() 疑似クラスは、兄弟要素のグループの中で指定された型の要素を、位置に基づいて選択します。
MDN web docs
めっちゃ似てますが、こちらは指定した要素の中で数を数えて指定する模様。
ちょっと文章だとややこしいので実際のコードと、その読み込み結果を見てみましょう。まずはnth-child。偶数個目が選択されるよう引数は2nにします。
<head>
<style>
div:nth-child(2n) {
background-color: #f0f;
}
</style>
</head>
<body>
<div>div1</div>
<div>div2</div>
<p>p1</p>
<div>div3</div>
<div>div4</div>
</body>
実行結果↓
そして、nth-of-type
<head>
<style>
div:nth-of-type(2n) {
background-color: #f0f;
}
</style>
</head>
<body>
<div>div1</div>
<div>div2</div>
<p>p1</p>
<div>div3</div>
<div>div4</div>
</body>
実行結果↓
わかりやすいように、divの中にpタグを一つ混ぜています。
すると、nth-childはpタグの数もカウントしているため、div3が選択されています。一方でnth-of-typeの場合はdivの個数だけを数えるため、div2とdiv4が選択されます。
こう見てみると、nth-childは不親切設計じゃない!?
なんで〇〇:nth-child(n)みたいに要素名指定させるのに、別の要素も数えちゃうの!?
逆にnth-childの方が都合がいいケースもあるかもしれないけど、基本的にはnth-of-typeの方が直感的で使いやすい感じがしますね。
では続いて、僕が混乱したクラス名とnth-childやnth-of-typeを組み合わせた時の挙動をみていきます。
nth-childの方から。
<head>
<style>
.a:nth-child(2n) {
background-color: #f0f;
}
</style>
</head>
<body>
<div class="a">div.a</div>
<div class="a">div.a</div>
<p class="a">p.a</p>
<div class="b">div.b</div>
<div class="a">div.a</div>
</body>
実行結果↓
どうやら偶数番目にある、クラス名がaの要素を選択している模様。
aのクラスがついたdivの個数ではないことに注意!
もし、クラス名がaだけでカウントしていたら、最後のdivタグも背景色が変わるはず。
つまり、クラス名の指定はあくまでも、nth-childの選択ロジックの中に対象のクラス名があれば動きますよというものなんですね。
続いて、nth-of-type
<head>
<style>
.a:nth-of-type(2n) {
background-color: #f0f;
}
</style>
</head>
<body>
<div class="a">div.a</div>
<div class="a">div.a</div>
<p class="a">p.a</p>
<div class="b">div.b</div>
<div class="a">div.a</div>
</body>
実行結果↓
こっちもnth-childと同じで、個数をカウントするロジックは要素ごとに行なっていて、ちょうどその選択された個数目に指定したクラス名があればという動きっぽいですが、上記の例だと、aクラスがついたpタグがカウントされている可能性もあるので、もう一つ試さないとわからないですね。
なんか別の記事でnth-of-typeはクラス名の個数を数えることができるって書いてあった気もするので…
ということで最終実験は、nth-of-typeはクラス名の個数をカウントできるのか実験です。
<head>
<style>
.a:nth-of-type(2n) {
background-color: #f0f;
}
</style>
</head>
<body>
<div class="a">div.a</div>
<div class="a">div.a</div>
<div class="a">div.a</div>
<div class="a">div.a</div>
<p class="a">p.a</p>
<div class="a">div.a</div>
<div class="b">div.b</div>
<div class="a">div.a</div>
<div class="a">div.a</div>
</body>
実行結果↓
はい、上記の結果から、nth-of-typeも要素の個数は要素ごとにカウントしており、クラス名で何番目かをしていることができないということが証明されました!
もし、クラス名でカウントを取っていればpタグの一つ下のdivの色が変わるはずなので。
結論として、nth-childとnth-of-typeの違いをまとめると以下の通り!
- nth-childは要素の種類に限らず個数をカウントする
- nth-of-typeは要素ごとに個数をカウントする
- どちらも特定のクラス名の要素の個数を数えることはできない
liタグみたいに割と規則的になりやすい構造ならすごい便利だけど、ちょくちょくspanとかdivが入り込んでくるような構造の要素には、奇数偶数でCSSを切り分けたいという時は、これらのセレクタにはちょっと気をつけないといけないですね〜
おそらく現状だと特定のクラス名の数を判定するセレクタはないと思われるので、地道にクラス名を与えて、切り分けるのが良さそうな感じがします。
以上、いっとくでした!
もし、もっと便利な裏技があるよ!とか間違いを発見していても立ってもいられなくなった方はお気軽にコメントしてください〜
おしまい!
コメント