1. ホーム
  2. CSS

【CSS】:nth-child と :nth-of-type の使い方|an+b で要素を狙い撃ちする方法

Share

テーブルの行を1行おきに塗り分けたり、グリッドの3つに1つだけ色を変えたり——そんな「何番目かで狙い撃ち」するスタイルは、CSS の :nth-child():nth-of-type() で実現できます。この記事では、偶数・奇数を表す even / odd から、3n2n+1 のような an+b 記法、そして混同しやすい :nth-child:nth-of-type の違いまでを、実際に動かせるコード付きで解説します。CSS の基本は分かるけれど、番号での指定がいまいち掴めないという初心者〜中級者の方が対象です。

「何番目」を狙うとはどういうことか

:nth-child() は、ある要素が「兄弟の中で何番目か」を条件にしてスタイルを当てる擬似クラスです。たとえばリストの3番目の項目だけ、テーブルの偶数行だけ、というように、HTML 側にクラスを増やさなくても順番だけでターゲットを絞り込めます。要素を1つずつ手作業で印付けする必要がないため、項目数が増えても CSS を書き換えずに済むのが大きな利点です。

カッコの中には数字をそのまま書くこともできます。li:nth-child(1) なら1番目、li:nth-child(3) なら3番目です。番号は 1 から数え、0 番目は存在しません。ただし本領を発揮するのは、これから紹介する even / oddan+b といった「複数の要素をまとめて指定する書き方」です。

偶数・奇数で塗り分ける(even / odd)

もっともよく使うのが、テーブルの行を1行おきに塗り分けるストライプ模様です。偶数番目を表す even、奇数番目を表す odd をカッコに入れるだけで実現できます。下のコードは実際に編集して試せます。CSS タブで evenodd に変えると、色の付く行が入れ替わるのを確認してみてください。

<table class="stripe">
  <thead>
    <tr><th>ID</th><th>商品名</th><th>価格</th></tr>
  </thead>
  <tbody>
    <tr><td>1</td><td>りんご</td><td>120円</td></tr>
    <tr><td>2</td><td>みかん</td><td>80円</td></tr>
    <tr><td>3</td><td>ぶどう</td><td>400円</td></tr>
    <tr><td>4</td><td>もも</td><td>300円</td></tr>
    <tr><td>5</td><td>なし</td><td>200円</td></tr>
    <tr><td>6</td><td>かき</td><td>150円</td></tr>
  </tbody>
</table>
.stripe {
  border-collapse: collapse;
  width: 100%;
  font-size: 15px;
}

.stripe th,
.stripe td {
  padding: 10px 14px;
  text-align: left;
}

/* 見出し行 */
.stripe thead th {
  background: #4a6cf7;
  color: #fff;
}

/* 偶数番目の行に色を付けてストライプ模様にする */
.stripe tbody tr:nth-child(even) {
  background: #eef2ff;
}

/* マウスを乗せた行を強調 */
.stripe tbody tr:hover {
  background: #dbe3ff;
}
Preview

ここで対象にしているのは tbody の中の tr です。見出し行の thead は別の親に属しているため、本文の行だけがきれいに 1, 2, 3… と数えられます。even2nodd2n+1 と同じ意味で、数字での書き方に慣れていれば後者で書いても構いません。

an+b 記法で間隔を指定する

:nth-child() のカッコには an+b という数式を書けます。a は「いくつおきか(間隔)」、b は「どこから始めるか(ずらし)」を表します。ブラウザは n に 0、1、2、3… を順に当てはめて計算し、その結果に当たる番号の要素を選びます。たとえば 3n なら、n=1 で 3、n=2 で 6、n=3 で 9 となり、3 つおきの要素が対象になります。

代表的な書き方と、それがどの番号にマッチするかを整理すると次のようになります。

書き方マッチする番号意味
3n3, 6, 9, …3 の倍数(3 つおき)
2n+11, 3, 5, …奇数(odd と同じ)
3n+11, 4, 7, …1 番目から 3 つおき
-n+31, 2, 3先頭から 3 つだけ
n+44, 5, 6, …4 番目以降すべて

少し分かりにくいのが -n+3 です。a がマイナスのときは、n=0 から数えると n=0 で 3、n=1 で 2、n=2 で 1、n=3 で 0 となり、0 以下は無視されるため結果として 1〜3 番目だけが残ります。「先頭からいくつまで」という上限を付けたいときの定番の書き方です。逆に n+4 は「4 番目以降すべて」という下限の指定になります。

実際に組み合わせて使ってみます。下のグリッドでは、3n で 3 つおきのセルを青く塗り、-n+3 で先頭 3 つに枠線を付けています。CSS タブで 3n3n+1 に変えると、青くなるセルが 1, 4, 7, 10 へずれます。数字を書き換えて、選ばれるセルがどう変わるか試してみてください。

<div class="grid">
  <div class="cell">1</div>
  <div class="cell">2</div>
  <div class="cell">3</div>
  <div class="cell">4</div>
  <div class="cell">5</div>
  <div class="cell">6</div>
  <div class="cell">7</div>
  <div class="cell">8</div>
  <div class="cell">9</div>
  <div class="cell">10</div>
</div>
.grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 10px;
}

.cell {
  height: 64px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  font-weight: bold;
  color: #555;
  background: #eceff4;
  border-radius: 8px;
}

/* 3つおき(3, 6, 9 番目)を青で塗る */
.cell:nth-child(3n) {
  background: #4a6cf7;
  color: #fff;
}

/* 先頭から3つ(1, 2, 3 番目)だけ枠線を付ける */
.cell:nth-child(-n + 3) {
  outline: 3px solid #f7884a;
  outline-offset: -3px;
}
Preview

:nth-child と :nth-of-type の違い

このふたつは「何番目か」を数える点では同じですが、数え方が決定的に違います。:nth-child() は要素の種類を問わず、兄弟全体の中で何番目かを数えます。一方 :nth-of-type() は同じ種類(同じタグ名)の要素だけを抜き出して数えます。この差が、思った要素にスタイルが当たらない原因になりがちです。

次のような HTML を考えてみます。div の中に見出しと段落が混在しているケースです。

index.html
<div class="box">
  <h2>タイトル</h2>   <!-- 1番目の子。pとしては数えない -->
  <p>1つ目の段落</p>  <!-- 2番目の子 / pとしては1番目 -->
  <p>2つ目の段落</p>  <!-- 3番目の子 / pとしては2番目 -->
</div>

「最初の段落」に色を付けたくて p:nth-child(1) と書いても、何も起こりません。1 番目の子は h2 であって p ではないため、条件に一致する要素が存在しないからです。ここで p:nth-of-type(1) と書けば、p だけを数え直して「最初の段落」を正しく選べます。

style.css
/* h2が1番目なので、これは1つも一致しない */
.box p:nth-child(1) {
  color: red;
}

/* pだけを数えるので、最初の段落に当たる */
.box p:nth-of-type(1) {
  color: blue;
}

ざっくり言えば、対象の要素だけがきれいに並んでいる(テーブルの tr やリストの li のように兄弟が全部同じタグの)ときは :nth-child() で十分です。見出しや画像など別のタグが混ざっていて、特定のタグだけを数えたいときは :nth-of-type() を選ぶ、と覚えておくと迷いません。両者の違いを表にまとめます。

擬似クラス数える対象向いている場面
:nth-child()種類を問わず兄弟全体兄弟がすべて同じタグのとき
:nth-of-type()同じタグの要素だけ別のタグが混在しているとき

末尾から数える :nth-last-child / :nth-last-of-type

数え始める向きを後ろからにしたいときは、:nth-last-child():nth-last-of-type() を使います。役割はそれぞれ :nth-child() / :nth-of-type() と同じで、違いは「末尾から数える」点だけです。たとえば li:nth-last-child(1) は最後の項目、li:nth-last-child(2) は後ろから2番目を指します。an+b も同じように使えるので、:nth-last-child(odd) なら末尾を基準にした奇数番目になります。

項目数が変動するリストで「最後の2つだけ余白を変えたい」といった、後ろからの位置を基準にしたい場面で重宝します。前から数えると項目が増減するたびに番号がずれてしまいますが、後ろから数えれば末尾の位置は変わらないためです。

狙った要素に当たらないとき

数えているのは「子」であることを思い出す

:nth-child() でつまずく原因の多くは、セレクタの種類と数える順番を混同していることです。.item:nth-child(2) は「2 番目の子であり、かつ .item でもある要素」という意味で、「.item の中の2番目」ではありません。まず親の中で 2 番目の子を探し、それが .item かどうかを確かめる、という順で評価されます。2 番目の子が別のクラスだった場合、一致する要素はなくなります。

余計な要素が番号をずらしていないか

HTML 上に見出しや非表示の要素、コメント以外の空要素などが紛れていると、それらも子として数えられて番号がずれることがあります。狙った番号に当たらないときは、ブラウザの開発者ツールで親要素の子を実際に並べて確認し、対象だけを数えたいなら :nth-of-type() へ切り替えるか、対象要素を専用の親で囲んで兄弟を揃えると安定します。先ほどのテーブル例で theadtbody を分けたのも、本文の行だけを 1 から数えさせるための工夫でした。

まとめ

:nth-child():nth-of-type() を使えば、HTML にクラスを足さずに「何番目か」でスタイルを当てられます。偶数・奇数のストライプには even / odd、一定間隔や範囲の指定には 3n-n+3 のような an+b 記法が使えました。n に 0、1、2… を順に入れて計算する仕組みを押さえれば、どの番号に当たるかを自分で見積もれます。:nth-child() は兄弟全体、:nth-of-type() は同じタグだけを数えるという違いがあり、別のタグが混在するときは後者を選ぶのが安全です。末尾を基準にしたいときは :nth-last-child() / :nth-last-of-type() を組み合わせて、狙った位置を的確に指定してみてください。

参考ページ