おい、調子はどうだ?
今日も元気に `
さて、今回はCSSの `:nth-child()` についてだ。「ああ、偶数行に色を塗るやつね `nth-child(even)` でしょ?」と思ったそこの君。おいおい、それだけでこの強力なセレクタをわかったつもりになっていたら、現場の複雑なデザイン要件にぶち当たったときに痛い目を見るぞ。
`:nth-child()` の真骨頂は、何と言ってもあの `an+b` という数式構文 だ。ここを完全に理解しているかどうかで、君のCSSの「格」が変わる。今日は、ブラウザの裏側の動きから、実務で明日から使えるド変態な(褒め言葉だ)実践テクニックまで、シニアの俺がみっちり叩き込んでやる。心してついてきな。
—
そもそも `:nth-child(an+b)` の数式、ちゃんと説明できるか?
まずは基礎の復習だ。なんとなくカンで書いてエラーを祈るようなコーディングは今日で卒業しよう。
`:nth-child(an + b)` の各文字の意味はこうだ:
- `n`: カウンター変数。`0` から始まり、`1, 2, 3…` と自動的にインクリメントされていく整数だ。
- `a`: 係数(ステップ)。`n` に掛かる数字で、何番おきに要素を選ぶかを決める。
- `b`: オフセット(基準点)。どこからカウントを開始するかを調整する。
ブラウザはこの数式を使って、「`n` に `0, 1, 2…` を代入していった結果得られるインデックスの要素」を上から順に血眼になって探している。
例えば、`nth-child(3n + 1)` という指定があったとしよう。ブラウザは裏側でこう計算している:
1. $n = 0$ のとき: $3(0) + 1 = 1$ (1番目の要素)
2. $n = 1$ のとき: $3(1) + 1 = 4$ (4番目の要素)
3. $n = 2$ のとき: $3(2) + 1 = 7$ (7番目の要素)
結果、「1番目、4番目、7番目、10番目……」という、3つ飛ばしの1番目を狙い撃ちできるわけだ。どうだ、数学の授業っぽくなってきただろ? でも、これがフロントエンドの実務で最強の武器になるんだ。
—
`even` と `odd` の正体
ちなみに、みんながよく使う `even`(偶数)と `odd`(奇数)は、実はこの数式構文の糖衣構文(シュガーシンタックス)に過ぎない。
- `nth-child(odd)` = `nth-child(2n + 1)`(1番目、3番目、5番目……)
- `nth-child(even)` = `nth-child(2n)` または `nth-child(2n + 0)`(2番目、4番目、6番目……)
ブラウザの内部処理としてはどちらも同じ数式として処理されている。豆知識として覚えておくと、後輩にドヤ顔できるぞ。
—
【実務で使える】コピペ即戦力のサンプルコード
理屈はこれくらいにして、現場で本当によくある要件をこの数式でどう解決するか、具体的なコードを見ていこう。今回は、ブログのカードグリッドや、データテーブルを想定したHTMLを用意した。
- カード 1 (TOP3・強調)
- カード 2 (TOP3・強調)
- カード 3 (TOP3・強調)
- カード 4 (4番目以降・少し薄く)
- カード 5 (3n+2の背景色)
- カード 6 (4番目以降・少し薄く)
- カード 7 (4番目以降・少し薄く)
- カード 8 (3n+2の背景色)
- カード 9 (4番目以降・少し薄く)
ここがポイント! `-n + 3` の魔法
コードのコメントにも書いたが、`:nth-child(-n + 3)` は実務で死ぬほど使う。
- $n = 0$ のとき: $0 + 3 = 3$ (3番目)
- $n = 1$ のとき: $-1 + 3 = 2$ (2番目)
- $n = 2$ のとき: $-2 + 3 = 1$ (1番目)
- $n = 3$ のとき: $-3 + 3 = 0$ (存在しないので無視される)
このように、「先頭から○個の要素を指定する(範囲指定)」 という芸業が、クラスを付与しなくてもCSS単体で完結してしまう。これがプリプロセッサ(Sass等)に頼らない、ピュアなCSSの底力だ。
—
⚠️ 現場でハマりがちな「罠(トラップ)」
さて、ここまでドヤ顔で解説してきたが、実務で `:nth-child` を使うときに誰もが一度はハマる「最大の罠」について話しておこう。
それは、「親要素の中にある、すべての兄弟要素がカウント対象になる」 という仕様の罠だ。
例えば、以下のようなマークアップがあったとする。
新着情報
お知らせ1
お知らせ2
お知らせ3
ここで `.wrapper p:nth-child(1)` と書いたとする。君は「最初の `
` タグ(=お知らせ1)」を選択したつもりだろう?
だが、ブブー、不正解だ。
`:nth-child(1)` が指し示すのは、`.wrapper` の中で「1番目に生まれた子ども(DOMツリー上の順番)」だ。つまり、この場合は `
` が1番目にあたるため、`.wrapper p:nth-child(1)` は何もヒットしない(pタグではないため)。 対策:現代のCSSは `:nth-of-type()` を使え、あるいは `:is()` を組み合わせろ
もし「特定のタグの種類の中で何番目」を指定したいなら、`:nth-child` ではなく `:nth-of-type()` を使うのがセオリーだ。これならタグの種類ごとにカウントしてくれる。
さらに、最近のモダンブラウザであれば、CSSセレクタのレベル4で導入された `:is()` や、これからの主役になる `:nth-child(an+b of
/ .wrapper の中にある p タグの中から、偶数番目のものを選ぶ(最新仕様) /
.wrapper :nth-child(even of p) {
background: #f9f9f9;
}
※ `of
—
シニアからのまとめ
`:nth-child()` の数式構文、怖くなかったろ?
要するに、ブラウザに「何番目から何番目までをどう料理してほしいか」を数学的に伝えるための共通言語だ。
JavaScriptでわざわざ要素をループさせてクラスを付与しなくても、CSSの数式を一行スマートに書いてあげるだけで、パフォーマンスも保てるし保守性も爆上がりする。
次に「特定の位置の要素だけデザイン変えて」とデザイナーから無茶振りをされたときは、クラス名乱立で逃げずに、ぜひこの `an+b` 構文を思い出してスマートに解決してくれ。期待しているぞ!

コメント