`:nth-of-type()`を使いこなす:DOMの「型」を正しく解釈するCSSの作法
フロントエンド開発の現場で、CSSの保守性に頭を抱えることはないだろうか?
「なぜかスタイルが当たらない」「意図しない要素まで色が変わってしまった」といったトラブルの多くは、CSSセレクタの解釈と、実際のHTML構造の微妙なズレから生まれる。特に `:nth-child()` と `:nth-of-type()` の違いを曖昧にしたまま書き進めると、後から泣きを見ることになる。
今日は、中級エンジニアなら絶対に押さえておきたい、`:nth-of-type()` の「型」に依存したスタイリングの真髄について話をしよう。
—
`:nth-child()` との決定的な違い
まず、基本を整理しよう。
- `:nth-child(n)`: 親要素内の「上から何番目の子要素か」をカウントする。タグの種類は問わない。
- `:nth-of-type(n)`: 親要素内の「指定したタグ名と同じ型を持つ要素の中で、上から何番目か」をカウントする。
ここが重要だ。ブラウザは `:nth-of-type()` が指定されたとき、「同じタグ名を持つ要素だけを抽出して、仮想的なリストを作成し、そのn番目を探す」という処理を行っている。
つまり、間に `
` や `` が混ざっていても、`div:nth-of-type(2)` と書けば、ブラウザは無視して「divだけ」をカウントしてくれる。この「混ざりもの」に強い特性こそが、実務でこの疑似クラスを選ぶ最大の理由だ。
—
実践:メンテナンス性を高めるコード例
例えば、記事詳細ページで「最初の段落だけ大きくして、それ以降の段落にはマージンを入れる」といったケース。これを `:nth-of-type()` で書くと非常にクリーンになる。
/ 記事本文内の段落に対するスタイリング /
.article-body p {
line-height: 1.8;
margin-bottom: 1.5rem;
}
/ 1番目の段落だけ強調する(型を意識した指定) /
.article-body p:nth-of-type(1) {
font-size: 1.25rem;
font-weight: bold;
}
/ 2番目以降の段落には区切り線を入れる(notを使って制御) /
.article-body p:not(:nth-of-type(1)) {
border-top: 1px solid #eee;
padding-top: 1rem;
}
このコードの利点は、仮にHTML構造の中に「広告バナー」や「注釈用div」が急に挿入されたとしても、`p` タグのスタイルが崩れにくいという点だ。`:nth-child` だと、「広告が挿入された瞬間にカウントがずれてスタイルが壊れる」という悲劇が起こりやすい。
—
ブラウザの裏側で起きていること
ブラウザのレンダリングエンジン(BlinkやWebKit)は、CSSルールが適用されるたびにDOMツリーを走査する。
`:nth-of-type()` は、単にインデックスを見るだけでなく、「要素の型(tagName)」をチェックするフィルタリング処理が走る。当然、`:nth-child` に比べるとわずかながら計算コストはかかるが、現代のブラウザ性能であれば無視していいレベルだ。
むしろ、「HTMLの構造変更に対してCSSがどれだけ耐性を持てるか」という保守コストの方が、パフォーマンスの微差よりも遥かに重要だと現場では判断すべきだ。
—
シニアからのアドバイス:使い分けの指針
現場でコードを書くとき、私は以下の基準で使い分けている。
1. 「構造が固定されている場合」:
リストアイテム(`
2. 「構造が動的に変わる可能性がある場合」:
CMSから出力されるHTMLや、複数の要素が混在するコンテナ内では、迷わず `:nth-of-type()` を使え。「どのタグか」を明示的に指定することで、未来の自分やチームメンバーが「このCSSが何に対して適用されているか」を直感的に理解できるようになる。
まとめ
`:nth-of-type()` は、単なる「n番目を選ぶツール」ではない。「HTMLのタグの種類という『型』を信用し、DOMのノイズに惑わされずに意図した要素を射抜くための道具」だ。
CSSは、書くことよりも「いかに壊れないように書くか」が問われる仕事だ。今日から、セレクタを書くたびに一度立ち止まって考えてみてほしい。「これは、構造が変わっても生き残れるセレクタか?」と。
その小さな意識の積み重ねが、君をただのコーダーから、信頼されるアーキテクトへと引き上げてくれるはずだ。

コメント