【実務・中級編】 :first-of-type と :last-of-type 疑似クラス – CSS実践ガイド

`:first-of-type` と `:last-of-type` を使いこなす:CSSセレクタの「泥臭い」真実

やあ。現場でCSSと格闘している諸君、お疲れ様。
今日はCSSのセレクタの中でも、一見地味だが、使いこなすと「おっ、わかってるね」と言われる `:first-of-type` と `:last-of-type` について掘り下げていこうと思う。

MDNを見れば「最初と最後のタグを選択する」と書いてある。だが、実務で痛い目を見るのはその「タグの種類(type)」という言葉の重みを読み違えたときだ。ここを正しく理解しているかどうかで、君の書くCSSの堅牢性が段違いに変わる。

1. なぜ「:first-child」ではなく「:first-of-type」なのか

多くの初学者は `first-child` を使いがちだ。「最初の子要素」を指すからね。だが、現場のHTMLは往々にして複雑だ。たとえば、DOM構造がこうなっていたらどうする?

警告文

メインコンテンツ1
メインコンテンツ2

ここで `.container > :first-child` を使うと、選択されるのは `p` タグだ。もし君が「最初の `div` にだけマージンをかけたい」と思っていたら、このセレクタは無力だ。

ここで登場するのが `:first-of-type` だ。これは「親要素の中で、そのタグ名を持つ最初の要素」をピンポイントで射抜く。兄弟要素に何が紛れ込んでいようが、自分と同じタグ名の奴らの中での「長男」を探し出す。この「タグ種別ごとのインデックス」という概念が、カオスなマークアップを生き抜く武器になるんだ。

2. ブラウザが裏側でやっていること

ブラウザのレンダリングエンジンは、DOMツリーを構築した後にスタイルを適用する。`:first-of-type` が呼ばれると、ブラウザは親要素の子供たちを走査し、「自分と同じタグ名を持つ要素」をフィルタリングして、そのリストのインデックス0番目を探す。

これ、実はパフォーマンスの観点で見ると `child` 系セレクタよりわずかにコストがかかる。だが、現代のモダンブラウザであれば体感できるほどの差はない。それよりも、「DOM構造の変更に対してどれだけ脆いか」を気にするべきだ。

例えば、ReactやVueのようなコンポーネント指向の開発だと、DOMは動的に生成される。`first-child` に依存したスタイルを書くと、後から修正で `div` の前に `p` が一つ追加されただけで、レイアウトが崩壊する。「堅牢なCSS」とは、DOMの些細な構造変化に動じないスタイルのことを言うんだ。

3. 実践:現場で即戦力になる「リストと境界線」の定石

よくあるのが、「リストの項目間に区切り線を引くが、最初と最後にはいらない」というケース。これを `border` と `:not()` で書くのもいいが、`:first-of-type` / `:last-of-type` を使った方が意図が明確だ。

.card-item {
/ 全項目に下の境界線を引く /
border-bottom: 1px solid #eee;
}

/ 最初の要素の上部の境界線を消す(もしあれば) /
.card-item:first-of-type {
border-top: none;
}

/ 最後の要素の下の境界線を消す(これが一番重要!) /
.card-item:last-of-type {
border-bottom: none;
}

注意点:クラス名との組み合わせ

現場で一番多いミスがこれだ。
`.item:first-of-type` と書いたとき、これは「`.item` というクラスがついている最初の要素」という意味ではなく、「親要素内で最初に出現する、`.item` クラスを持っている要素」という意味ではない。

正しくは、「親要素内で、`.item` というクラスを持つ要素群の最初」ではなく、「親要素内で、タグ名が同じもののうち最初のものが、たまたま `.item` クラスを持っていたら適用される」という挙動だ。

これにハマると、「なぜか2番目の `.item` にスタイルが当たらない」という怪奇現象に遭遇する。セレクタは「タグ名+クラス」の組み合わせで考えろ。 これがCSSアーキテクトとしての鉄則だ。

4. プロからのアドバイス:セレクタは「過信」するな

`:first-of-type` は強力だが、複雑なネスト構造で多用しすぎると、後からコードを読んだ人間(未来の君自身を含む)が「どの要素に適用されているのか」を特定するのに苦労する。

  • DOM構造をいじくり回さないと実現できないスタイルは、そもそも設計が間違っている可能性がある。
  • 可能であれば、ユーティリティクラス(`.is-first`, `.is-last` など)をJavaScriptやテンプレートエンジンで付与する方が、保守性は圧倒的に高い。

CSSのセレクタだけで魔法をかけようとせず、HTMLの構造をクリーンに保つこと。それが一番の近道だ。

さて、現場に戻ってこの知識を試してみてくれ。もし「このケースはどう書くのがベストだ?」という悩みがあれば、いつでも相談に乗るよ。コードは正直だ。書いた人間の思考の深さが、そのまま反映されるんだからな。健闘を祈る。

コメント

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