nth-child・nth-of-type(+of selector)

# 編集履歴
- 2/14
    - 一部、間違っていた表記の修正
    - 追記（おまけ）のタイトルにて、クラス名を使った指定・nth-child(n of ```<selector>```),nth-lastに関する内容の追加
    - 既存の```.class:nth-chlid```類の書き方をof ```<selector>```のsyntaxと区分ができるようにする
- 2/12-2/13
    - nth-childとnth-of-typeの違いのみ記述

# 背景
nth-child・nth-of-typeのpseudo-classを使ってWEB制作タスクに対応したことがありました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674843/bf9de4be-07b1-4cae-af67-9135aabf41a9.png)
（デザインは大体こんな感じでした）

ただ、タスクを終えてからもnth-childかnth-of-typeがどのように違っていて、どの状況でどのように使われるかについてはまだ身についていなかったと思います。

そのため、「似ているように見えるが、使い方をちゃんと覚えておきたい！」という気持ちから本記事でまとめたみたいと思いました。

# 概要
## 共通点
[1] nth-childやnth-of-type両方とも、**特定の要素（element）を指定してスタイルを適用させることが可能**です。上記のサンプルように偶数目のカラムのみ色をつけることなどが代表的で、細かくは「2番目のh3要素のみにmargin-topを8pxぐらい入れたい」とかで応用もできます。
[2] 両方とも、カッコ（）の値を指定するルールは同じです。
```css
.hoge p:nth-child(value) {
    color: DeepPink;
}
```
- 定数（1,2,3...nなど）
    - 簡単にn番目の要素を指定するためのセレクターです
    - JSの配列とは違い、0から始まりません（1,2,3...)
    - 0以上の定数を値としてもらいます
- odd/even
    - oddは奇数単位の要素を指定します
    - evenは偶数単位の要素を指定します
- An+B式のFormula(n: 0,1,2,3...)
    - 数式を指定し、
    - nは0から始まる定数、AやBは定数が入ります
        - -n+3, 2n-1などを入れることができまs
    - odd/evenより幅広い対応ができます
- 定数ともAn+Bの数式とも、結果値が0であれば対象外になります
- 1番目や最後番目を選びたい時に使うセレクターがあります
    - first-child, first-of-type
        - nth-child(1), nth-of-type(1)
    - last-child, last-of-type
        - nth-last-child(1), nth-last-of-type(1)


## 違い
サンプルコードは以下になり、nth-childとnth-of-typeそれぞれの動きがどのように変わるか書きました。

```html
<div class="foo">
    <h1>First heading 1 element</h1>
    <p>First paragraph element</p>
    <p>Second paragraph element</p>
    <h2>First heading 2 element</h2>
    <p>Third paragraph element</p>
    <h3>First heading 3 element</h3>
    <p>Fourth paragraph element</p>
    <p>Fifth paragraph element</p>
</div>
```


### nth-child
```css
.foo p:first-child {
    color: pink;
}
```
```css
.foo p:nth-child(2) {
    color: pink;
}
```

<details><summary>結果</summary>


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674843/cb540134-ba27-40ea-baab-576f2c0fef64.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674843/f47dd9e6-7747-44e8-9b6a-82e406400323.png)

（first-childが1番目ではなかった。。！？）
</details>

特定要素のグループの**全体からn番目**を軸として算出します。
h1, h2, h3を含めるため、fooクラス内部を基準としてn番目に要素が存在しないと、セレクターで要素を読んでも指定されないことがあります。

<details><summary>より詳しく</summary>

```html
<div class="foo">
    <h1>First heading 1 element</h1> <!-- first-child -->
    <p>First paragraph element</p> <!-- nth-child(2) -->
    <p>Second paragraph element</p> <!-- nth-child(3) -->
    <h2>First heading 2 element</h2> <!-- nth-child(4) -->
    <p>Third paragraph element</p> <!-- nth-child(5) -->
    <h3>First heading 3 element</h3> <!-- nth-child(6) -->
    <p>Fourth paragraph element</p> <!-- nth-child(7) -->
    <p>Fifth paragraph element</p> <!-- last-child -->
</div>
```
つまり、fooクラスを基準としてn番目のelement childを指定していることになっています。


```js
const foo = document.querySelector(".foo")
console.dir(foo)
```
このJSコードを入れて検証すると、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674843/d4f0630c-928c-41a1-b366-fef854d54fbd.png)

のようにchildの順番になっていることがわかりました！
</details>

### nth-of-type
```css
.foo p:first-of-type {
    color: pink;
}
```
```css
.foo p:nth-of-type(2) {
    color: pink;
}
```

<details><summary>結果</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674843/675cbc7a-e07e-4125-bc73-6fddc934191e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674843/d3a962f2-dea0-46f7-98ce-4abbd2efc64b.png)

</details>

**指定した要素**を軸として算出します。.foo p:nth-of-typeだとすると、pタグ以外の要素(h1,h2,h3など）は考慮せず、pタグが基準になります。

## 応用
今回は、ちょっとアレンジされたサンプルです！

```html
<!-- #1 途中でdivが入っている -->
<div class="foo">
  <p>First paragraph element</p>
  <p>Second paragraph element</p>
  <p>Third paragraph element</p>
  <p>Fourth paragraph element</p>
  <div><p>Fifth paragraph element</p></div>
  <p>Sixth paragraph element</p>
  <p>Seventh paragraph element</p>
  <p>Eight paragraph element</p>
  <div><p>Nineth paragraph element</p></div>
  <p>Tenth paragraph element</p>
  <p>Eleventh paragraph element</p>
  <p>Twelfth paragraph element</p>
</div>
```

```html
<!-- #2 上位タグがarticle一つのみ -->
<div class="foo">
  <article>
    <h1>Article's first heading 1 element</h1>
    <p>Article's first paragraph element</p>
    <h2>Article's first heading 2 element</h2>
    <p>Article's second paragraph element</p>
    <p>Article's third paragraph element</p>
    <section>
      <h3>Article's first heading 3 element</h3>
      <p>Article's fourth paragraph element</p>
      <p>Article's fifth paragraph element</p>
    </section>
    <h2>Article's second heading 2 element</h2>
    <p>Article's sixth paragraph element</p>
    <p>Article's seventh paragraph element</p>
  </article>
</div>
```
### An + B
###### nth-child

```css
.foo p:nth-child(2n+3) {
    color: pink;
}
```

<details><summary>結果</summary>

1番目のコード(#1)：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674843/8ae5fde5-8a9e-4340-b6b6-e29b746edecf.png)


2番目のコード(#2)：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674843/d7d2de3c-10cc-4780-8eef-ba1a43f56c93.png)



</details>

<details><summary>解説</summary>

:::note info
**前提**
2n+3 → nが0,1,2...の順番に上がり、3・5・7・9・11・13の順番に上がります。
:::

- 1番目のコード(#1)：
1. ```<p>First</p>```からnth-child(1)として指定
2. p:nth-child(5)とp:nth-child(9)は、pタグとして該当しないため一旦対象外
3. ```<div>```の内部のpの場合は、またfirst-childやlast-childの条件を満たす上に、2n+3には対象外になるため適用されない
4. 結果的に3・7・11番目のpタグのスタイルが適用される

- 2番目のコード(#2)：
1. .foo直下のp:nth-childに該当する要素はないため、.foo直下のpタグは全部対象外
2. 1番目のarticleでは、２・４・５番目にpタグがあり、その中5番目のpタグはセレクターの対象になるため、スタイルが適用される
3. 2番目のsectionでは、２・3番目にpタグがあり、その中3番目のpタグ同じようにスタイルをもらう
4. 最後のarticle内部で、12・13番目のchildでpタグがまたあり、その中13番目のpタグが同じようにスタイルをもらう

</details>


###### nth-of-type

```css
.foo p:nth-of-type(2n+3) {
    color: pink;
}

```

<details><summary>結果</summary>

1番目のコード：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674843/842b9369-f850-4e52-a0e2-dbd161661ee8.png)


2番目のコード：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674843/6d13db31-ef63-494f-8d2f-f72eaa015eea.png)


</details>

<details><summary>解説</summary>

:::note info
**前提**
2n+3 → nが0,1,2...の順番に上がり、3・5・7・9・11・13の順番に上がります。
:::


1番目のコード：
1. fooの12個のchild要素の中、pタグのみ指定する。その中、div内部のpタグは対象外になる
2. 
3番目のpタグは```<p>Third</p>```になるが、
5番目の```<div><p>Fifth</p></div>```ではなく、その次の```<p>Sixth</p>```になる。
7番目はそこから2n足された```<p>8th</p>```になり、
9番目は```<div><p>Nineth paragraph element</p></div>```から2n離れている11番目のpタグが選ばれる。
3.```<div><p></p></div>```系のタグは、2n+3の対象外のため、スタイルなし

2番目のコード：

1. .foo直下のp:nth-of-typeに該当する要素はないため、.foo直下のpタグは全部対象外
2. articleは以下の上段のpタグから計算していく。そうすると、上から3番目の```<p>Article's third paragraph element</p>```(nth-childとしては5)の要素にスタイルが適用される
→ articleタグ中には合わせて**5つのpタグ**があり、nth-of-typeとして指定した場合には他の要素は計算対象に入らない
3. sectionブロックからも同じようにnth-of-typeが1から始まる。ただ、sectionタグの配下にはpタグが2個しかなく、2n+3の対象外になるため、スタイルなし
4. article下段のpタグの場合、2n+3=5に当たる最後のpタグ```<p>Article's seventh paragraph element</p>```が対象になり、スタイルが適用される

</details>

###### 途中のdiv pはどのように動くのか

<details><summary>解説</summary>

結論から申し上げますと、新しいdivタグを基準としてnth-child(1),nth-child(2)...の順番になります。

```js
const foo = document.querySelector(".foo")
console.log(foo.children)

const fooDiv = document.querySelectorAll(".foo div")
console.dir(fooDiv)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674843/dd2ff98d-f6d9-430e-885d-46e1067e6260.png)

#1のdiv.fooの直下で取得されたchildでは写真のようにp,p,..div,..pとして取得されます。
その中、.foo divの要素それぞれについてもpタグをchildとして格納していることがわかります。(querySelector・querySelectorAllとして検証可)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674843/ad7161e8-dc1d-4cb5-b17c-19b21ab28c53.png)

そのため、p:first-childなどで指定すると、.fooクラスの1番目のpタグだけでなく、その条件を満たす内部のdivのpタグまで含まれたりすることがあります。

#2の場合は.fooとして取得するとchildがarticleのみかかってきますが、
articleを基準でh1:first-child, p:nth-child(2),...の順番に計算されます。

そのため、.fooクラスを基準ではp:nth-childやp:nth-of-typeがかかってきませんが、
内部のarticle, sectionにもp:nth-childに該当する要素が見つかり、それらに対して適用されていく感じです。

</details>

# 追記（おまけ）
こちらは私への反省にもなります。
元々は「nth-childとnth-of-type二つの使い方があり、これだけではないか？」と思ったのですが、juner様のご指摘とMDNドキュメントでの確認により重要な内容が漏れていたことを確認したため、こちらにて追加で記述したいと思いました。

## nth-last-
逆順番からnth-childやnth-of-typeを算出するセレクターです。
nth-last-child(1)はlast-childと同じ、nth-last-of-type(1)はlast-of-typeと同じ機能を持っています。

## nth-child(n of [S])：of-selector
nth-childでもnth-of-typeと同じような効果が出せる構文として、[CSS Selector Level 4](https://drafts.csswg.org/selectors/#typed-child-index)から実装されました。
また、それだけでなく、[S]のセレクターで複合セレクター(```<complex-selector-list>```)が使えたりします。
この構文は既存の```selector.nth-child```とは動きが違い、これはただの要素が基準ではなく、クラス名が含まれている複合セレクターになる時に現れます。

## クラス名＋要素の指定（selector.nth-child vs of ```<selector>```）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674843/db060197-cb58-4227-9d56-10d44b0c80be.png)

[MDNのドキュメント](https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-child)に出ている通りに、

```css
ul.one > li:nth-child(-n + 3 of .noted) {
  background-color: tomato;
  border-bottom-color: seagreen;
}

ul.two > li.noted:nth-child(-n + 3) {
  background-color: tomato;
  border-bottom-color: seagreen;
}
```
のお互いは動きが違います。

### selector.nth-child・selector.nth-of-type
最初にnth-childまたはnth-of-typeに該当する要素を探し、その中指定したクラス名もあったらスタイルが入ります。

上記のMDNのサンプルのul.twoの場合がそうであり、-n+3で1~3番目までのliを選別した後、その中から.notedクラスも持っているDiegoとCaterinaが対象になります。そのため、li.notedが基準になって動きません。

また、nth-of-typeについては、[このMDNドキュメント](https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-of-type)によりますと```nth-of-class```を探すことはできないと書いてあります。

### of ```<selector>```
この場合、最初から```<li class="noted">item</li>```を満たしている要素をフィルターし、該当する要素にスタイルを適用させます。
li class="noted"にあたるDiego・Caterina・Gila・Lexiが選ばれ、その中```-n+3```に該当するDiego、Caterina、Gillaがスタイルをもらいます。

```nth-of-class```を探す時に、このof ```<selector>```であるため、クラス名が含まれている場合にはnth-of-typeより強力かもしれません。

# まとめ
- nth-childは指定したセレクターについて全てのchild要素を基準で算出し、nth-of-typeは同じ要素を算出するpseudo-class
- ただ、nth-childにもof ```<selector>```を使えばnth-of-typeと同じように、またはより強い機能が使える
- 特に、クラス名が含まれている場合にはof ```<selector>```について知っていればより強力
    - ```selector.nth-child```・```selector.nth-of-type```については、ベースになる要素を探す→その中に指定されている**クラス名もある**要素にスタイルが入る
    - 一方、:nth-child(n of ```<selector>```)は最初からセレクターの条件を満たす要素を基準で算出ができる


# 感想
いつもの通りの考えですが、CSSって本当に勉強すればするほどおもろいことがたくさんで、今の時点でも学ぶことが多いなーと思いました！

# 参考
https://www.freecodecamp.org/news/nth-child-vs-nth-of-type-selector-in-css/
サンプルコードはこちらのものが今回のスタイルを勉強するときにとても役に立ち、```<div class="foo">```を囲んでリユースいたしました。
[CSS Selector Level 4](https://drafts.csswg.org/selectors/#typed-child-index)
[MDNドキュメント-nth-child](https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-child)
[MDNドキュメント-nth-of-type](https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-of-type)
[MDNドキュメント-nth-last-child](https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-last-child)
[MDNドキュメント-nth-last-of-type](https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-last-of-type)