使用 CSS nth-child 必須要注意的事情

之前有寫過一篇 利用 :nth-child() 讓網頁展示商品時左右對齊 的文章,裏面有稍微提到:nth-child()的使用方法。

其實:nth-child()好用的地方就在於他可以針對每個元素做個別的樣式設定,不用再像以往一樣用程式判斷然後算半天。不過我最近發現,有一些排版,沒辦法直接使用:nth-child()達到我想要的效果,所以最後我還是改用 jQuery 撰寫。如果你常使用:nth-child()寫網頁,不妨可以參考一下唷。

再次引用 W3C 的解釋(請特別記住這句話,接下來的範例,受到這句話的影響非常深刻唷)

:nth-child(n) 選擇器匹配屬於其父元素的第 N 個子元素,不論元素的類型。n可以是數字、關鍵詞或公式。

【範例】規定屬於其父元素的第二個子元素的每個 p 的背景色:p:nth-child(2) { background:#ff0000; }

CSS3 :nth-child() 選擇器 / W3SCHOOL

看完如果似懂非懂的朋友,沒關係,請先記住這句話,下面會再詳細解說。這篇文章先當作大家已經會使用基本的:nth-child()

範例

話不多說,直接上範例,CSS & HTML 語法請看我的 codepen,或參考以下 DEMO:

以上這個網頁結構,分作主課程 (WordPress, CSS, Html) 以及子課程 (install plugin, install theme…等) 兩種;在範例中,我想要做的效果是「當子課程是偶數欄時,背景會變咖啡色」。

左邊是用 CSS 的:nth-child(odd)語法,右邊則是用 jQuery 的:odd selector,大家可以看到最後呈現的兩種效果不太一樣。(是的,你沒看錯,odd 是奇數不是偶數,為什麼我會用 odd 而不用 even,後面會解釋)

就常理而言,應該是右邊的「Use jQuery(:odd)」會比較好閱讀,左邊的欄位變色感覺有些不連貫。如果你有看 codepen 的語法,應該會發現我都是使用:odd來控制,那為什麼計算的結果不一樣呢?難道是 CSS 跟 jQuery 對 odd 的計算方式不同嗎?

其實可以說是,也不是。事實上,這跟 HTML DOM 有比較大的關聯。

版面解析

讓我們先來拆解這個 HTML 版面。這是一個課程清單表,主課程底下會有很多子課程,所以用類似「合併儲存格」的功能,把最前面的主課程欄位合併,這樣在看課程的時候較一目了然。因此,我是這麼寫的:

HTML

我用.class-wrap包住最大的課程類別,再用.content包住子課程。所以簡化版的 HTML 會長這樣:

HTML

接著,回到原本我們想做的網頁效果:「子課程的偶數欄位要變色」。

我們想要變色的 class 是.content,然後是偶數(even) 欄位。假使我們用:nth-child來寫的話,正常毫無疑問會這麼寫:

CSS

但你會發現,用:nth-child(even)後,居然是奇數欄位變色了!! (也可以直接編輯我的 codepen 看結果唷)

揪竟是為什麼呢!?只能說:nth-child是個非常奇妙的東西,尤其碰到像範例這種複雜的排版,整個計算方式會跟常理認知的不太一樣呢!讓我們來慢慢的、一步步了解吧。


一、先了解:nth-child(n)的初始值是 0 還是 1 ?

:nth-child(n)的初始值是 1 ,依序 1、2、3、4 這樣算下來。因此沒有:nth-child(0)這種東西

二、再了解:nth-child(n)的定義

重點 ★ 請把剛才我請你記住的那句話,關於:nth-child(n)的定義,拿出來複習一下:「:nth-child(n)選擇器匹配屬於其父元素的第 N 個子元素,不論元素的類型」。

接著,我們再把剛剛的 CSS code.content:nth-child(even),改成跟定義一樣的句子:「.content選擇器,匹配其父元素.class-wrap的第偶數(even)個子元素」

… 好吧,我覺得大家一定看不懂,讓我改用白話文說一遍 (嗚嗚,要講解這一部分好難啊,不要逼我自暴自棄 T^T)

  1. 先找到.content的父元素:.class-wrap
  2. 找出.class-wrap底下的所有子元素,以剛剛的語法範例來看,第 1 個子元素是class="class"的主課程標題,第 2 個子元素才是class="content"的子課程 1 。 主課程標題 1 子課程 1 子課程 2
  3. 因此,原本我們以為「子課程 1 」會是匹配父元素的第 1 個元素,但因為.content前面還有一個.class,所以「子課程 1 」變成了匹配父元素的第 2 個元素。
  4. 再重新把.content:nth-child(even)拿回來看,其實符合偶數(even)的元素是這些:

這樣大家清楚嗎?因為前面多了一個不是.content的 class,但他也是.class-wrap的子元素阿!所以全部算下來,原本我們以為的偶數會是奇數、奇數會變偶數。因此我的範例語法才會寫:odd而非:even

如果了解,就讓我們繼續進行下去。

三、為什麼 n 的計算不是從 1 到 100 呢?

因為:nth-child(n)是以父元素.class-wrap作為起始點。假設第一個主課程底下有 4 個子課程,他的元素依序計算為 1、2、3、4;但,到了第二個主課程又會重新從 1 開始計算,並不會從 5 繼續數下去。

這就是為什麼我們看到左邊的範例會感覺參差不齊,但如果你把每個.class-wrap都當作一個段落,就會發現他其實偶數的元素還是會變色的。


圖解

那,到底每個子課程的:nth-child(n)是多少?

還是不太清楚的朋友,可以再看看我寫的 codepen:http://codepen.io/mukiwu/full/nmlkt ,然後隨意點選任何子課程的欄位。你會看到如下結果:

如果你點選了任意子課程的欄位,可以在紅底的區塊看到一些數字。

簡單總結:

  • 「Use CSS nth-child(odd)」:以主課程作為區塊,每個主課程結束以後,會重新開始計算。這邊出現的數字是該欄位的:nth-child(n)的 n 值
  • 「Use jQuery(:odd)」:單純計算有多少子課程,不受主課程影響,所以會從 0 算到最大個數。這邊出現的數字是所有子課程的 index 值

以上是兩種寫法主要的差別。

利用 jQuery :odd 撰寫

就如前面所說,為了視覺的平衡,我們幾乎都會採用右邊的表現手法,所以可以改用 jQuery 撰寫:

JS

只是要特別注意的是,jQuery(":odd")的初始值是 0 不是 1,所以第 1 個子課程是偶數、第 2 個子課程才是奇數… 以此類推。

我們以為偶數的欄位是奇數,以為奇數的欄位是偶數,這樣的情況會再度發生。

總結

如果你會用到像我這樣的排版,直覺的使用CSS nth-child來撰寫的話,也許會碰到同樣的問題。因此,可以嘗試使用 jQuery 解決。如果有可以直接用 CSS 解掉的方法,也歡迎告訴我唷:)

以後,我會將一些寫的較漂亮的範例轉移到 codepen,如果你喜歡我寫的範例,也歡迎到我的 codepen 支持我唷

想對你說 (ノ>ω<)ノ

感謝您閱讀到最後,對文章有任何疑問歡迎留言給我,我會盡快回覆。

Faceook / 不定時分享前端資訊與新知,歡迎追蹤!

 

如果這篇文章對您有幫助,請幫我點擊下方的廣告,讓我有更多的動力寫寫寫 (๑•̀ㅂ•́)و✧

guest
3 則留言
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Carl Shih
Carl Shih
5 years ago

謝謝了~!! 剛開始學這個真的容易沒注意到是”父”元素的第幾個!

LCM
LCM
2 years ago

用CSS做出類似jQuery的效果
https://codepen.io/jimmyliao11/pen/gBYMxN

粉絲團