【実務・中級編】 nth-of-type疑似クラスと要素型の関係 – CSS実践ガイド
CSS
フロントエンドの現場で仕事をしていれば、誰もが一度はCSSのセレクタ指定で頭を抱えた経験があるはずだ。「あれ、なんでこのスタイルが当たらないんだ……?」「構造は合っているはずなのに、なぜか隣の要素まで赤くなってしまう……」。
特に、リストやカードグリッドなど、動的にDOMが生成されるパーツをコーディングしているとき、子孫要素の指定ミスはバグの温床になりがちだ。
中でも多くのコーダーや中級エンジニアが勘違いしやすいのが、今回取り上げる `:nth-of-type` と、その双子の兄弟である `:nth-child` の違いだ。公式ドキュメントにはサラッと「同じ型の要素をカウントします」と書いてあるが、この「型の概念」をブラウザが裏側でどう処理しているかを理解していないと、実務で痛い目を見る。
今日は、シニアの視点から、この `:nth-of-type` の本質と、現場で本当に使えるスマートな使いこなし方を徹底的に解説しよう。明日からのコーディングが確実に変わるはずだ。
—
1. そもそも `:nth-of-type` とは何者か?
まずは基本の復習からいこう。
`:nth-of-type(n)` は、「親要素の中で、自分と同じ『HTMLタグ名(要素型)』を持つ兄弟要素の中から数えて何番目か」を条件にマッチさせる疑似クラスだ。
言葉だけだと抽象的なので、まずは現場でよくある「罠」から見ていこう。
多くの人がハマる「あの罠」
次のようなHTML構造があったとする。ブログの記事詳細ページや、お知らせリストなどで非常によく見る形だ。
最初の見出し
段落テキスト 1
段落テキスト 2
段落テキスト 3
ここで、「2番目の要素にスタイルを当てたい」と思って、よく考えずに `:nth-child(2)` を書いたとしよう。
/ 事故の元になりやすい書き方 /
.article-body :nth-child(2) {
color: #e03131; / 赤色にしたい /
}
さて、ブラウザはどう解釈するだろうか?
`:nth-child(2)` は、「親要素(`.article-body`)の中にある、すべての兄弟要素の中で2番目のもの」を指す。
つまり、この場合、2番目の要素は `
` の次にある `
段落テキスト 1` だ。これは意図通りかもしれない。
しかし、もしCMSの仕様変更などで、`
` の直前にアイキャッチ画像 `` が挿入されたらどうなるか?
最初の見出し
段落テキスト 1
段落テキスト 2
この瞬間、`:nth-child(2)` が指す「2番目の要素」は `
` に変わってしまう。段落を赤くしたかったはずが、気づけば見出しが真っ赤に染まっている。これが、DOM構造の変動に弱い `:nth-child` の恐怖だ。
`:nth-of-type` ならどうなるか?
ここで `:nth-of-type(2)` の登場だ。
/ プロが選ぶ堅牢な書き方 /
.article-body p:nth-of-type(2) {
color: #2f9e44; / 緑色にしたい /
}
`:nth-of-type` は、「`
` というタグを持つ要素だけ」を抽出し、その中で2番目のものを探しに行く。
つまり、途中に `
` が入ろうが、`
` が割り込もうが、`
` タグのカウントだけに集中するため、意図しない要素にスタイルが漏れ出すことがなくなる。これが、私たちが `:nth-of-type` を愛する理由だ。
—
2. ブラウザは裏側でどう処理しているのか?
フロントエンド・スペシャリストとして、ブラウザのレンダリングエンジンの気持ちになって考えてみよう。ブラウザは、CSSセレクタを右から左(Key selector から親方向)に向かって評価していく。
`:nth-of-type(n)` に遭遇したとき、ブラウザは裏側で次のようなプロセスを踏んでいる。
1. 要素の特定: まず対象となる要素(例: `p`)のタグ名を確認する。
2. 兄弟ノードのフィルタリング: その要素の親ノードが持つ子要素のリストから、自分と同じタグ名を持つものだけを抽出した「仮想的なインデックスリスト」を頭の中で組み立てる。
3. インデックスの照合: 抽出されたリストの中で、指定された番号(`n` や `2n+1` など)に自分が合致するかを判定する。
ここで重要なのは、「異なるタグが混在していても、カウントの対象外になるだけで無視される」という点だ。
例えば、`div > p:nth-of-type(2)` と書いた場合、div直下にある `` や `` は、カウントの分母には一切カウントされない。そのため、HTMLの構造に多少のマークアップの揺れ(装飾用タグの追加など)があっても、デザインが崩れにくい高い耐性を発揮する。
—
3. 実務で即戦力になるコードパターン
理屈はこれくらいにして、現場のコードベースですぐに使える実践的なサンプルを見ていこう。コピペして挙動を確認してみてほしい。
実例:CMS出力の自由なテキストエリアに対する交互背景(ゼブラストライプ)
ブログの本文や、ユーザーが自由に投稿できるリッチテキストエリアでは、どんなタグがどんな順番で入ってくるか予測がつかない。そんなときこそ `:nth-of-type` の独壇場だ。
最初の導入段落です。ここは通常サイズ。
2番目の段落です。少し強調したい。
注意書きのバナーが入ることもある
3番目の段落です。間にdiv挟まってるけど正しくカウントしたい!
4番目の段落です。
/
【CSS実装】
divなどの他の要素が挟まっていても、
タグだけでグループ化して
偶数番目の段落に背景色を敷く
/
.rich-text p:nth-of-type(even) {
background-color: #f8f9fa;
padding: 1.2rem;
border-left: 4px solid #7950f2;
border-radius: 0 4px 4px 0;
}
/ ついでに奇数番目には別の調整を入れたりもできる /
.rich-text p:nth-of-type(odd) {
margin-bottom: 1.5rem;
}
このコードの美しいところは、`.box-note` のような割り込み要素が存在しても、CSSの計算が狂わない点だ。もしここで `:nth-child(even)` を使っていたら、divが挟まった瞬間に偶奇の判定が狂い、意図しない行に背景色がついてしまう。
—
4. ⚠️ 現場でハマりがちな「落とし穴」と注意点
ここで、シニアから後輩へ、現場でよくある事故の注意点を共有しておこう。
罠:「あれ、効かない?」と思ったら、親要素のタグがバラバラだった件
`:nth-of-type` は、あくまで「同じタグ名」をカウントする。
もし、次のようなHTML構造で、親要素を無視してセレクタを組んだ場合、期待通りに動かないことがある。
この場合、`p:nth-of-type(1)` と書くとどうなるだろうか?
それぞれの `p` 要素にとっての「親」は、直近の `div` 要素になる。つまり、それぞれの `div` の中には `p` が1つしか存在しないため、すべての `p` が「1番目のp」として判定されてしまう。
全体を通して何番目か、ではなく、「それぞれの親から見たときの何番目か」というスコープの概念を忘れないようにしよう。親を跨いだ連番を指定したい場合は、CSS GridやFlexboxのレイアウト調整、あるいはJSでの制御を検討すべきサインだ。
—
まとめ:適材適所でCSSをスマートに操ろう
`:nth-child` と `:nth-of-type` は、どちらが優れているというものではない。
- `:nth-child`: リストのグリッド(`
- ` が並ぶような均質な構造)で、純粋に順番だけを厳密に制御したいとき。
- `:nth-of-type`: ブログ記事の本文や、タグが混在するラッパー内など、HTMLの構造変化に対して頑健性(ロバストネス)を持たせたいとき。
実務において、保守性の高いコードを書くということは、「将来の仕様変更やマークアップの揺れに耐えられる設計にする」と同義だ。
無暗に `:nth-child` で力技のセレクタを書くのではなく、`:nth-of-type` の特性を正しく理解し、適材適所に使い分けられるようになれば、あなたのCSSは一段も二段も洗練されたプロのコードになるはずだ。
さあ、今日のタスクのCSSファイルを開いて、無駄なグリッチをスマートに書き換えてやろう。
コメント