在使用 CSS 選擇器時,:nth-of-type 和 :nth-child 的行為很容易混淆,而且 :nth-of-type 無法配合 class selector 使用,這篇整理兩者的差異和解決方案。
核心差異
:nth-child(n)
根據元素在父元素中的位置(不分類型)計算順序。
1
2
3
4
5
|
<div>
<p>第 1 個子元素</p> <!-- p:nth-child(1) ✓ -->
<span>第 2 個子元素</span>
<p>第 3 個子元素</p> <!-- p:nth-child(3) ✓ -->
</div>
|
1
2
|
p:nth-child(2) { color: red; } /* 不匹配,第2個子元素是 span */
p:nth-child(1) { color: red; } /* 匹配第一個 p */
|
:nth-of-type(n)
根據元素在父元素中相同類型的順序計算。
1
2
3
4
5
|
<div>
<p>第 1 個 p</p> <!-- p:nth-of-type(1) ✓ -->
<span>span</span>
<p>第 2 個 p</p> <!-- p:nth-of-type(2) ✓ -->
</div>
|
1
|
p:nth-of-type(2) { color: red; } /* 匹配「第 2 個 p」,不受 span 影響 */
|
為何 .class:nth-of-type 無法正常運作?
這是最常見的踩雷點。:nth-of-type 只看 HTML 標籤類型,完全忽略 class。
1
2
3
4
5
|
<div>
<p class="aaa">項目 1</p>
<p class="bbb">項目 2</p>
<p class="aaa">項目 3</p>
</div>
|
1
2
3
4
5
|
/* 你可能期望選到第 1 個 .aaa,但實際上無法如預期運作 */
.aaa:first-of-type { color: red; }
/* 瀏覽器的理解是:類型為 .aaa 的第一個元素 */
/* 但 CSS 不把 class 視為「類型」,所以行為不可預測 */
|
實際上瀏覽器會把上面的選擇器解讀為:「第一個 p 元素,且它有 .aaa class」,也就是等同於:
1
|
p:first-of-type.aaa { color: red; } /* 即:第一個 p 且有 .aaa class */
|
實際範例對比
1
2
3
4
5
6
|
<ul>
<li class="highlight">項目 A</li>
<li>項目 B</li>
<li class="highlight">項目 C</li>
<li>項目 D</li>
</ul>
|
1
2
3
4
5
|
/* 想選第 2 個 .highlight(項目 C)—— 這樣行不通 */
.highlight:nth-of-type(2) { background: yellow; }
/* 實際效果等同於:第2個 li 且有 .highlight class */
/* 結果:不會選中任何元素(第2個 li 沒有 .highlight) */
|
解決方案
方案 1:改用 :nth-child 配合 class
1
2
|
/* 選擇第 3 個 li(即項目 C),且確認它有 .highlight class */
li:nth-child(3).highlight { background: yellow; }
|
方案 2:使用 :is() 選擇器(現代瀏覽器)
1
2
3
|
/* 選擇 ul 內第 2 個有 .highlight class 的 li */
/* 注意:這仍然是基於位置,不是 class 的計數 */
li:nth-child(2 of .highlight) { background: yellow; }
|
:nth-child(n of selector) 是 CSS Selectors Level 4 的新語法,2023 年後各主流瀏覽器已支援,可以直接對特定選擇器計算順序。
方案 3:JavaScript 動態處理
1
2
|
const highlights = document.querySelectorAll('.highlight');
highlights[1].style.background = 'yellow'; // 選第 2 個 .highlight(index 從 0 開始)
|
總結
| 選擇器 |
計算基準 |
可搭配 class? |
:nth-child(n) |
父元素中的位置(含所有類型) |
可以(但計數包含其他類型) |
:nth-of-type(n) |
父元素中相同標籤的順序 |
不行(class 不是類型) |
:nth-child(n of selector) |
父元素中符合選擇器的順序 |
可以(CSS Level 4,現代瀏覽器支援) |