「nth-childとnth-of-typeの違いをわからず使ってしまっている」
「ブログやYoutube動画を見ていて、発信者によってnth-childとnth-of-typeを使っている人がバラバラだから違いが余計わからない」
「◯番目というセレクタがうまく適用できないことがある」
CSSで要素を選択する際によく使用されるnth-childとnth-of-typeの違いについて、混乱してしまった経験はありませんか?
2つの擬似クラスは似たような役割を果たしますが、実は微妙な違いが存在します。
本記事では、nth-childとnth-of-typeの使い方や動作の違いについて詳しく解説していきます。
「同じようなもの」という認識では実務のときに思わぬトラブルになるかもしれませんので初学者の方は必ず押さえておくことをおすすめします。
またどちらを使用すべきか迷っている方や、より正確なスタイリングを行いたい方にとっても今回の内容は非常に役立つでしょう。
動画も用意しているので併せてご覧ください。
CSSのnth-childとnth-of-typeの大きな違い
まずHTMLとCSSで以下のようなマークアップをしておきましょう。
nth-childとnth-of-typeの違いをわかりやすく体験するための題材とします。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="./style.css" />
<script src="./script.js" defer></script>
</head>
<body>
<h1>container</h1>
<div class="container">
<div class="item1"></div>
<div class="item2"></div>
<div class="item3"></div>
</div>
<h1>wrapper</h1>
<div class="wrapper">
<div class="item1"></div>
<div class="item2"></div>
<div class="item3"></div>
</div>
</body>
</html>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container,
.wrapper {
display: flex;
}
.container div {
width: 200px;
height: 200px;
border: 1px solid #333;
}
.wrapper div {
width: 200px;
height: 200px;
border: 1px solid #333;
}
CSSのセレクタにnth-childを指定する方法
まずnth-childを使ってみます。
containerの3つのブロックの中で一番左のブロックにだけ背景色をつけたい場合は以下のようにします。
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container,
.wrapper {
display: flex;
}
.container div {
width: 200px;
height: 200px;
border: 1px solid #333;
}
.wrapper div {
width: 200px;
height: 200px;
border: 1px solid #333;
}
/* ここから追加 */
.container div:nth-child(1) {
background: red;
}
containerのブロックは3つともdivタグになっていて、セレクタを「.container div : nth-child(1)」とすると「class=”container”の子要素のなかで1番左のブロック」という意味になります。
そのためクラス名やid名をセレクタに書いていないにも関わらず1つのブロックにだけ背景色をつけることに成功しました。
そもそもnth-child自体を知らなかった方はこの機会に覚えておきましょう。
CSSのセレクタにnth-of-typeを指定する方法
続いてnth-of-typeですが考え方は同じです。
今度はwrapperのブロックについて一番左のブロックに背景色をつけてみます。
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container,
.wrapper {
display: flex;
}
.container div {
width: 200px;
height: 200px;
border: 1px solid #333;
}
.wrapper div {
width: 200px;
height: 200px;
border: 1px solid #333;
}
.container div:nth-child(1) {
background: red;
}
/* ここから追加 */
.wrapper div:nth-of-type(1) {
background: red;
}
nth-childのときと同じようなスタイルになりましたね。
セレクタを「.wrapper div : nth-of-type(1)」としたことで「class=”wrapper”の子要素のなかで、左から数えて1番目のdivタグ」という意味です。
nth-childとnth-of-typeの大きな違いとは?
それではnth-childとnth-of-typeに違いはあるのでしょうか?
HTMLを以下のように修正して別の検証をしてみましょう。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="./style.css" />
<script
src="https://yubinbango.github.io/yubinbango/yubinbango.js"
charset="UTF-8"
></script>
<script src="./script.js" defer></script>
</head>
<body>
<h1>container</h1>
<div class="container">
<!-- ここを追加 -->
<p>test</p>
<div class="item1"></div>
<div class="item2"></div>
<div class="item3"></div>
</div>
<h1>wrapper</h1>
<div class="wrapper">
<!-- ここを追加 -->
<p>test</p>
<div class="item1"></div>
<div class="item2"></div>
<div class="item3"></div>
</div>
</body>
</html>
containerとwrapperの子要素にそれぞれpタグを追加しました。
すると早速containerのブロックについては先ほどまであった赤い背景色が無くなってしまいました。
実はこれがnth-childとnth-of-typeの大きな違いを表現しています。
nth-childをもう少し正確に表現すると「class=”container”の子要素のなかで1番左のブロック(セレクタ名は無視して数える)」になるからです。
多くの初学者の方は知らずに作業していると思います。
実はnth-childを使って「.container div : nth-child(1)」と書いても「divタグのうち1番目」という意味にはなっておらず、「class=”container”の子要素のなかで1番目」になっています。
最初のHTMLの状態ではclass=”container”の子要素はdivタグのみだったので問題なかったのですが、pタグを子要素に追加したことで条件が変わってしまったんです。
先ほどのようなスタイルに戻すにはCSSを以下のように修正する必要があります。
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container,
.wrapper {
display: flex;
}
.container div {
width: 200px;
height: 200px;
border: 1px solid #333;
}
.wrapper div {
width: 200px;
height: 200px;
border: 1px solid #333;
}
/* ここを修正 */
.container div:nth-child(2) {
background: red;
}
.wrapper div:nth-of-type(1) {
background: red;
}
もう一度赤い背景色をつけることができました。
containerの中の子要素は4つになったのでブロックの1番目にするには「.container div : nth-child(2)」として2番目を指定することになります。
一方nth-of-typeについては「class=”wrapper”の子要素のなかで、左から数えて1番目のdivタグ」なのでwrapperの子要素が増えても変わりません。
現状のトレンドとしてnth-childとnth-of-typeのどちらが正しいという風にはなっていません。
今回やったような後からHTMLが書き換わることがないサイトやアプリであれば、どちらを採用しても結果は変わらないからです。
「サイト運営をしながらHTMLがどんどん変更されていく」ということがわかっているのであればnth-of-typeの方が良いかもしれません。
初学者の方はまず2つの違いをしっかり理解して、両方の書き方に対応できるように練習しておきましょう。
CSSでよく使うnth-childのパターン
最後にnth-childでよく使うパターンを紹介しておきます。
nth-of-typeよりもnth-childの方が使う人が多い印象があります。
そのため他人のコードでnth-childを使った書き方を見る機会があるはずなので、今のうちにnth-childの頻出パターンを練習しておきましょう。
まずは以下のようなHTML、CSSを使います。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="./style.css" />
<script src="./script.js" defer></script>
</head>
<body>
<div class="cards">
<div class="card">
<h2>Web制作</h2>
</div>
<div class="card">
<h2>マーケティング</h2>
</div>
<div class="card">
<h2>動画編集</h2>
</div>
<div class="card">
<h2>アプリ開発</h2>
</div>
<div class="card">
<h2>SEOコンサル</h2>
</div>
<div class="card">
<h2>デザイン</h2>
</div>
</div>
</body>
</html>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
margin: 16px;
background: #eee;
}
.cards {
width: 1000px;
display: flex;
align-items: center;
flex-wrap: wrap;
}
.card {
width: calc(1000px / 3);
padding: 56px 40px;
background: #fff;
box-shadow: 8px 8px 16px rgba(0, 0, 0, 0.5);
}
<div class=”card”>のカードが複数あり、それらのうち特定の場所のみ選択してスタイルを当てることを考えていきます。
n番目のカードのみを指定する
「2番目のカードのみ背景色を変える」といった特定のひとつだけを指定する場合は引数に数字を入れると良いです。
数字は1から始まる整数を入れるルールです。
また順番はHTMLにて書いた上から下に向かっての順番です。
デザインの見た目は関係ないので注意しましょう。
/* 省略 */
.card:nth-child(1) {
background: yellow;
}
/* 省略 */
.card:nth-child(2) {
background: yellow;
}
最初のカード、最後のカードを指定する
ちなみに番号ではなく最初と最後は別の書き方も可能です。
書き方が違っていても「1番目のことだな」とわかるようになっておく必要がありますので紹介です。
/* 省略 */
.card:first-child {
background: yellow;
}
/* 省略 */
.card:last-child {
background: yellow;
}
first-child、last-childともにカッコ( )が無くなるので注意してください。
偶数、奇数のカードをすべて指定する
ここまでは単体のカードを指定していましたが、複数同時に指定したいときもあります。
例えば「偶数番目のカード」などパターンにできる状況です。
/* 省略 */
.card:nth-child(2n) {
background: yellow;
}
反対に「奇数番目のカード」は以下のように書きます。
/* 省略 */
.card:nth-child(2n + 1) {
background: yellow;
}
少し算数の考え方が必要ですね、nには0から始まる整数が入ると思ってください。
2nだと2の倍数なので偶数です、ちなみにnに0が入ると2nの結果も0になりますので無視されます。
2nが偶数であるのならば奇数は1を足してあげれば良いので2n+1になります。
nの倍数に当たるカードを全て指定する
偶数の時の考え方を利用すると「3の倍数」など倍数に該当するパターンにも使用できることがわかります。
例えば3番目と6番目を選択するときは3の倍数ということで以下のように書きます。
/* 省略 */
.card:nth-child(3n) {
background: yellow;
}
n番目以降の全てを指定する
倍数ではないですが「4番目以降のすべて」というようなパターンもあります。
/* 省略 */
.card:nth-child(n + 4) {
background: yellow;
}
nには0が最初に入るので0+4で4になり、nに1が入り1+4で5になり、nに2が入り2+4で6になるという具合です。
今回のレイアウトは6番目までしかないので4番目以降は4,5,6までが対象になります。
もしカードがもう1枚増えて7番目が最終になったら7番目のカードも自動的に指定されることになります。
最初は戸惑うかもしれませんが簡単な算数なので慣れると思います。
nth-childを使ったセレクタの指定パターンは自分が使わなくても他人のコードやサンプルコードで見かけた時に理解できるようになっておきましょう。
nth-childのofについて
最近では新しいCSSとしてnth-childの引数にofを使った詳細な指定ができるようになりました。
今まで紹介してきた書き方を使えば大体のことはできるのですが、最近ではofを使った書き方をする人が増えてきたので一緒に紹介します。
初心者の方はまずは前章までの内容を理解することを優先して余裕のある方だけ取り組むと良いでしょう。
まず以下のようなHTMLがあるとして進めていきます。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="./style.css" />
<script src="./script.js" defer></script>
</head>
<body>
<h1>container</h1>
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
<h1>wrapper</h1>
<div class="wrapper">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
<h1>inner</h1>
<table>
<tr>
<td>AAA</td>
<td>0001</td>
</tr>
<tr>
<td>BBB</td>
<td>0002</td>
</tr>
<tr>
<td>CCC</td>
<td>0003</td>
</tr>
<tr>
<td>DDD</td>
<td>0004</td>
</tr>
</table>
</body>
</html>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
padding: 32px;
}
.container,
.wrapper {
display: flex;
}
.container div {
width: 200px;
height: 200px;
border: 1px solid #333;
}
.wrapper div {
width: 200px;
height: 200px;
border: 1px solid #333;
}
まずnth-childの引数にofを指定することで「〇〇の▲▲」という具合にセレクタを限定させることが可能です。
例えばh1タグが現状3つあるうちの2番目の「wrapper」の文字だけ色を変えるには以下のように書きます。
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
padding: 32px;
}
.container,
.wrapper {
display: flex;
}
.container div {
width: 200px;
height: 200px;
border: 1px solid #333;
}
.wrapper div {
width: 200px;
height: 200px;
border: 1px solid #333;
}
/* ここを追加 */
:nth-child(2 of h1) {
color: blue;
}
基本的な「n番目」という使い方と同じですね。
「:nth-child」とセレクタを指定せずに書くことで現在の表示しているHTML全体を検索対象としてh1を探して2番目を指定したという感じです。
こちらを特定の親要素のなかを検索対象にするには以下の書き方にすれば可能です。
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
padding: 32px;
}
.container,
.wrapper {
display: flex;
}
.container div {
width: 200px;
height: 200px;
border: 1px solid #333;
}
.wrapper div {
width: 200px;
height: 200px;
border: 1px solid #333;
}
:nth-child(2 of h1) {
color: blue;
}
/* ここを追加 */
:nth-child(2 of .container .item) {
background: red;
}
「:nth-child(2 of .container .item)」とすることでcontainerの中のitemの中で2番目という意味です。
「.container .item:nth-child(2)」と同じだと思って良いでしょう。
基本的には限定させる使い方が多いですが、あえて限定させずに条件に一致するものを同時選択するという使い方もできます。
引数から「.container」を削除してみましょう。
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
padding: 32px;
}
.container,
.wrapper {
display: flex;
}
.container div {
width: 200px;
height: 200px;
border: 1px solid #333;
}
.wrapper div {
width: 200px;
height: 200px;
border: 1px solid #333;
}
:nth-child(2 of h1) {
color: blue;
}
/* ここを修正 */
:nth-child(2 of .item) {
background: red;
}
直接的に親子関係になっていないけどclass名が同じものを同時に選択すると便利な場面はありますよね。
他にも引数に擬似クラスを指定することもできます。
例えばテーブルの奇数行だけ背景色をつけたいとします。
通常であれば以下のようにすることが多いです。
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
padding: 32px;
}
.container,
.wrapper {
display: flex;
}
.container div {
width: 200px;
height: 200px;
border: 1px solid #333;
}
.wrapper div {
width: 200px;
height: 200px;
border: 1px solid #333;
}
:nth-child(2 of h1) {
color: blue;
}
:nth-child(2 of .item) {
background: red;
}
/* ここを追加 */
table {
border-collapse: collapse;
}
td {
border: 1px solid #666;
padding: 8px 16px;
}
tr:nth-child(odd) {
background: skyblue;
}
ブログサイトやコーポレートサイトなどの静的なコンテンツでは問題ないのですが、Webアプリのようにユーザーの操作によって動的に変わるものは少々困ったことになります。
例えばJavaScriptの機能で「hiddenというクラスが付与された行は非表示にする」というものが同時に設定してあったとしましょう。
ユーザーが特定の情報を削除、非表示にするケースです。
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
padding: 32px;
}
.container,
.wrapper {
display: flex;
}
.container div {
width: 200px;
height: 200px;
border: 1px solid #333;
}
.wrapper div {
width: 200px;
height: 200px;
border: 1px solid #333;
}
:nth-child(2 of h1) {
color: blue;
}
:nth-child(2 of .item) {
background: red;
}
table {
border-collapse: collapse;
}
td {
border: 1px solid #666;
padding: 8px 16px;
}
tr:nth-child(odd) {
background: skyblue;
}
/* ここを追加 */
.hidden {
display: none;
}
HTMLで3番目のtrタグに手書きでclass=”hidden”を追加して実験してみましょう。
以下のように互い違いに背景色がつかなくなってしまいます。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="./style.css" />
<script src="./script.js" defer></script>
</head>
<body>
<h1>container</h1>
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
<h1>wrapper</h1>
<div class="wrapper">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
<h1>inner</h1>
<table>
<tr>
<td>AAA</td>
<td>0001</td>
</tr>
<tr>
<td>BBB</td>
<td>0002</td>
</tr>
<!-- ここを修正 -->
<tr class="hidden">
<td>CCC</td>
<td>0003</td>
</tr>
<tr>
<td>DDD</td>
<td>0004</td>
</tr>
</table>
</body>
</html>
理由としては検証ツールを確認するとわかります。
画面上は非表示にしてもHTML上は残るためセレクタの指定は変わらないことが原因です。
これだと少々デザイン上よくないのでofを使った書き方で以下のようにCSSを修正してみます。
ポイントとしては「hiddenのついていないn番目」とすることです。
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
padding: 32px;
}
.container,
.wrapper {
display: flex;
}
.container div {
width: 200px;
height: 200px;
border: 1px solid #333;
}
.wrapper div {
width: 200px;
height: 200px;
border: 1px solid #333;
}
:nth-child(2 of h1) {
color: blue;
}
:nth-child(2 of .item) {
background: red;
}
table {
border-collapse: collapse;
}
td {
border: 1px solid #666;
padding: 8px 16px;
}
tr:nth-child(odd) {
background: skyblue;
}
.hidden {
display: none;
}
/* ここを追加 */
:nth-child(odd of tr:not(.hidden)) {
background: skyblue;
}
こちらで期待通りのデザインにすることができました。
ofを使うことでマクロにもミクロにも検索対象をコントロールできるので便利ですね。