MUKI AI Summary
使用 :nth-child() 能為每個元素設置獨特樣式,避免複雜程式計算。但某些排版無法直接達到預期效果,需改用 jQuery。:nth-child(n) 選擇父元素的第 N 子元素,n 可為數字或公式。範例中,偶數子課程背景變色,CSS 和 jQuery 的 :odd 效果不同,因 HTML DOM 計算差異。CSS 以父元素計算,jQuery 則從 0 開始。若遇類似問題,可用 jQuery 解決,或尋找更簡便的 CSS 方法。
如喜歡範例,可至 codepen 支持。...
之前有寫過一篇 利用 :nth-child() 讓網頁展示商品時左右對齊 的文章,裏面有稍微提到 :nth-child()
的使用方法。
其實 :nth-child()
好用的地方就在於他可以針對每個元素做個別的樣式設定,不用再像以往一樣用程式判斷然後算半天。不過我最近發現,有一些排版,沒辦法直接使用 :nth-child()
達到我想要的效果,所以最後我還是改用 jQuery 撰寫。如果你常使用 :nth-child()
寫網頁,不妨可以參考一下唷。
再次引用 W3C 的解釋(請特別記住這句話,接下來的範例,受到這句話的影響非常深刻唷):
:nth-child(n)
選擇器匹配屬於其父元素的第 N 個子元素,不論元素的類型。n
可以是數字、關鍵詞或公式。【範例】規定屬於其父元素的第二個子元素的每個 p 的背景色:
CSS3 :nth-child() 選擇器 / W3SCHOOL
p:nth-child(2) { background:#ff0000; }
看完如果似懂非懂的朋友,沒關係,請先記住這句話,下面會再詳細解說。這篇文章先當作大家已經會使用基本的 :nth-child()
。
範例
以上這個網頁結構,分作主課程 (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 版面。這是一個課程清單表,主課程底下會有很多子課程,所以用類似「合併儲存格」的功能,把最前面的主課程欄位合併,這樣在看課程的時候較一目了然。
因此,我是這麼寫的:
<div class="class-wrap"> <div class="class">Wordpress<br /><span class="week">(Wednesday)</span></div> <div class="content"> <div class="icon"> <div class="icon-border">W</div> </div> <div class="course">install plugin</div> <div class="time">19:00 ~ 21:00</div> <div class="index"></div> </div> <div class="content"> <div class="icon"> <div class="icon-border">W</div> </div> <div class="course">install theme</div> <div class="time">14:00 ~ 18:00</div> <div class="index"></div> </div> <div class="content"> <div class="icon"> <div class="icon-border">W</div> </div> <div class="course">post your first atricle</div> <div class="time">18:00 ~ 20:00</div> <div class="index"></div> </div> </div>
我用 .class-wrap
包住最大的課程類別,再用 .content
包住子課程。
所以簡化版的 HTML 會長這樣:
<div class="class-wrap"> <div class="class">主課程標題 1</div> <div class="content">子課程 1</div> <div class="content">子課程 2</div> <div class="content">子課程 3</div> </div> <div class="class-wrap"> <div class="class">主課程標題 1</div> <div class="content">子課程 1</div> <div class="content">子課程 2</div> </div>
接著,回到原本我們想做的網頁效果:「子課程的偶數欄位要變色」。
我們想要變色的 class 是 .content,
然後是偶數(even) 欄位。假使我們用 :nth-child
來寫的話,正常毫無疑問會這麼寫:
.content:nth-child(even) { background: #A69689; }
但你會發現,用 :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 語法: .content:nth-child(even)
,改成跟定義一樣的句子:「.content
選擇器,匹配其父元素 .class-wrap
的第偶數(even
)個子元素」
... 好吧,我覺得大家一定看不懂,讓我改用白話文說一遍 (嗚嗚,要講解這一部分好難啊,不要逼我自暴自棄 T^T)
- 先找到
.content
的父元素.class-wrap
。 - 找出
.class-wrap
底下的所有子元素,以剛剛的語法範例來看,第 1 個子元素是class="class"
的主課程標題,第 2 個子元素才是class="content"
的子課程 1 。 主課程標題 1 / 子課程 1 / 子課程 2 - 因此,原本我們以為「子課程 1 」會是匹配父元素的第 1 個元素,但因為
.content
前面還有一個.class
,所以「子課程 1 」變成了匹配父元素的第 2 個元素。 - 再重新把
.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 撰寫:
var contentOdd = $("#jquery-trick .content:odd"); contentOdd.css("background" , "#A69689"); contentOdd.children(".course").css("color","#eee");
只是要特別注意的是,jQuery(":odd")
的初始值是 0 不是 1,所以第 1 個子課程是偶數、第 2 個子課程才是奇數... 以此類推。
我們以為偶數的欄位是奇數,以為奇數的欄位是偶數,這樣的情況會再度發生。
總結
如果你會用到像我這樣的排版,直覺的使用 CSS nth-child
來撰寫的話,也許會碰到同樣的問題。因此,可以嘗試使用 jQuery 解決。如果有可以直接用 CSS 解掉的方法,也歡迎告訴我唷:)
以後,我會將一些寫的較漂亮的範例轉移到 codepen,如果你喜歡我寫的範例,也歡迎到我的 codepen 支持我唷
謝謝了~!! 剛開始學這個真的容易沒注意到是”父”元素的第幾個!
這個其實很饒舌 XDD,我自己後來看文件的時候也才恍然大悟
用CSS做出類似jQuery的效果
https://codepen.io/jimmyliao11/pen/gBYMxN