iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 7
10
Modern Web

金魚都能懂的 CSS 選取器 - 金魚都能懂了你還怕學不會嗎系列 第 7

CSS 層疊式宣告 - 讓你快速選到特定元素內的物件的選取器

  • 分享至 

  • xImage
  •  

本系列文章已集結成書,並於書中添加一些新篇章及細節補充,有興趣的朋友可至天瓏書局選購,感謝各位支持
購書連結 https://www.tenlong.com.tw/products/9789864344994?list_name=b-r30-zh_tw
讓我們好好善用CSS選取器吧


在開始解說之前,讓我們先回到最基本的知識,CSS 原名 Cascading Style Sheets,翻譯成中文的名稱有「串樣式列表級聯樣式表串接樣式表階層式樣式表」(翻譯名稱出自維基百科)。從翻譯上面來解讀的話,Amos 把幾個關鍵字抓出來,也就是「串接」跟「層疊或階層」,拉回到我們的主題來看的話,CSS 的選取器至今為止有哪個選取方式是具備剛剛所述的串接?沒錯!就是組合式宣告方式,那麼層疊又是指哪種選取方式的特性呢?就讓我們繼續看下去~

如果你看過了上一篇CSS 選取器的組合式宣告的話,那麼這一篇文章正是前一篇的延續,因為[CSS 選取器的組合式宣告在選取器跟選取器之間是不可以有空格的,但是今天我要談的選取器恰好就是要談選取器之間的空格。

在 CSS 中一定會用到的選取方式就是「選取器A 選取器B」這種方式,這邊需要注意到的是,兩個選取器之間至少具備一個或多個空格,這意思是我要選取到左方選取器A內的選取對象B,如果覺得這樣太過概念的話,回到官方的用語來說,層疊式宣告就是所謂的 後代選取器(Descendant combinator) ,也就是說只要是物件 A 的後代且後代是 B 物件的話,就可以被選到,不多說我們立馬用原始碼來看看

<div class="news">
	<h1>Amos</h1>
</div>

<div class="hot">
	<h1>Alvee</h1>
</div>

上方這一段 HTML 原始碼可以分成兩個區塊,一個是.news 一個是 .hot,在兩個區塊中都各有一個 h1 標題,接著我們來設定以下 CSS 並了解 CSS 設定方式的作用

/*將所有的標題都設定為 36像素字級*/
h1{ font-size: 36px; }

/*將 news 裡面的 h1 設定成紅色字*/
.news h1{ color: red; }

/*將 hot 裡面的 h1 設定成粉紅色字*/
.hot h1{ color: pink; }

上面的 CSS 寫法可以看到,我們可以將共用的項目設定在 h1,接著使用父層的 class 名稱差異來選取到不同物件空間內的子層 h1,是不是有文章一開始說到的「層」與「疊」的概念出現了?!各位應該可以發現到跟 Amos 之前寫的 CSS 選取器的群組式宣告 中實務應用的寫法很相似,也就是將共用的項目設定在共通的 CSS 選取器,接著將差異的部分設定在差異的 CSS 選取器中,但是這種利用不同父層來設定子層的方式更加的彈性且乾淨。且如果搭配了群組式宣告與組合式宣告的話,那個變化性就變得非常靈活且強大了。Amos 曾經在某一段時期可是非常喜歡這樣的設定方式呢!

暗藏毒藥的層疊式選取器

瞭解層疊選取方式之後,我們就可以讓我們的原始碼變乾淨了,省下了許多的 class 名稱,讓 HTML 回歸最純淨無污染的狀態,就像下方這樣

<section class="news">
	<h2>最新消息</h2>
	<ul>
		<li><a href="#">...略</a></li>
		<li><a href="#">...略</a></li>
		<li><a href="#">...略</a></li>
	</ul>
</section>

<section class="events">
	<h2>近期活動</h2>
	<ul>
		<li><a href="#">...略</a></li>
		<li><a href="#">...略</a></li>
		<li><a href="#">...略</a></li>
	</ul>
</section>

天哪~多麼乾淨的原始碼(讚嘆~),我只需要在一組資料的最外面設定一個 class 名稱就可以了,裡面完全可以不需要去添加那一堆看起來讓我增加閱讀困擾的 class 名稱啊,接著我們就可以像下面這樣來設定我的 CSS

.news,
.events{ ...略 }

.news h2,
.events h2{ ...略 }

.news ul,
.events ul{ ...略 }

.news ul li,
.events ul li{ ...略 }

.news ul li a,
.events ul li a{ ...略 }

看到了嗎?我利用了群組式宣告搭配現在的層疊式宣告方式就可以做完一堆複雜的設定了,原始碼也乾乾淨淨的,多美好的一種撰寫方式啊!

如果!!!你覺得上面這種寫法非常棒的話,你只對了一半,這看似美好的撰寫方式,雖然可以讓你的 HTML 原始碼變得非常乾淨,但卻會讓你的 CSS 原始碼變得異常累贅且效能低落!且你撰寫的層級越多,你的 CSS 效能就越差!

瀏覽器對 CSS 的選取流程

從 mozilla 曾經揭露的瀏覽器中對 CSS 的選取方式來了解(來源頁面網址我忘了,若有網友願意提供給我會很感謝您的),在 .news ul li a 這一長串選取器的選取流程會是由右至左的選取,也就是瀏覽器會先選取到 a 標籤後再看他的父層是誰,然後再看他的父層的父層是誰,然後再看他的父層的父層的父層是誰,然後再看他的父層的父層的父層的父層是不是 .news (我知道看到這你開始想打我了)。

在上述過程中,大致的意思就是你只要有一個流程不符合我們所寫的選取器層疊結構,你前面的尋找都是做白工啊,且一層層的比對真的是耗時費工(雖然電腦速度快到你無感),但若有大量的這類寫法的話,你那的電腦再快都會被拖累效能的,更不用說你面試時拿出這樣的作品出去的話,你看看面試的技術部門主管會用什麼眼光來看你的能力?(當然也有一些單位是不在意啦)

曾經聽過一個說法,某單位的 CSS 選取器被要求不可超過兩層,也曾聽過某技術主管說如果面試看到面試者的 CSS 選取器寫超過 6 層的話會超級大扣分,當然如果你寫出了世界奇觀的層數的話,我想一定可以讓面試官留下很深刻的印象的(或許是件好事???)

層疊選取器寫幾層最好

由於每間公司的狀況跟技術債層次高度不同,說真的這一類只求固定答案的問題,Amos 真的是被問到白眼翻到背後好幾圈了,我們回過問題的核心來思考,看能不能得到答案,CSS 層疊寫法會寫出很多層的原因「可能」有以下幾個

  • 自己當初 HTML 架構規劃不佳
  • 前人留下的 HTML 架構不夠彈性
  • 之前的 CSS 結構寫得不好,為了優先權只好多寫幾層
  • 專案需求變更、目標變更、開發團隊變更、老闆變更(咦)
  • 不管啦,反正都是 them 的錯

上面可以看到前三個原因應該就是我們最重點的項目了,解決方式簡單的說,能重構就重構,不能重構就在能修改的範圍下,盡量微幅修改 code 讓它擁有更多的彈性,至於 CSS 的寫法的話能盡量讓層次少一點就盡量吧,例如原本可能要超過 6 層的,我可以讓他省下一兩層也好啊,事實上,在多數的情況下,我可能會有下面這樣的寫法

<!-- HTML -->
<section class="section news">
	<h2 class="section-title">最新消息</h2>
	<ul class="list">
		<li class="list-item">
			<a href="#" class="list-item-link">...略</a>
		</li>
		...略
	</ul>
</section>

<section class="section events">
	<h2 class="section-title">近期活動</h2>
	<ul class="list">
		<li class="list-item">
			<a href="#" class="list-item-link">...略</a>
		</li>
		...略
	</ul>
</section>
/* CSS */
.section{ 共用設定...略 }
.section .section-title{ 共用設定...略 }
.section .list{ 共用設定...略 }
.section .list-item{ 共用設定...略 }
.section .list-item-link{ 共用設定...略 }

.news .list-item-link{ 差異設定...略 }
.events .list-item-link{ 差異設定...略 }

這樣的原始碼一樣不會髒到哪去,維護跟彈性也還是能夠繼續維持,那有沒有更多變化?當然絕對是有的,就看專案需求跟目的還有開發方式來決定要怎麼寫才會更好,所以別再跟我要一個答案了,沒有絕對的答案,只有最適合專案的解/寫法。看到這邊還無法理解的話,那...有些事情就跟交女友一樣是急不來的,等你經驗多一點你就會懂了,乖乖認真去做專案吧。(對不起我忘了你沒有女友)

以上就是今天的 金魚都能懂的 CSS 選取器 - CSS 層疊式宣告 - 讓你快速選到特定元素內的物件的選取器,如果文中描述有誤歡迎各位前輩不吝指正,各位金魚我們明天見~

金魚都能懂的教學系列

鐵人雙主題挑戰中,歡迎訂閱一波

金魚都能懂的這個網頁畫面怎麼切

立刻訂閱 CSS可樂的網站/頻道享受精彩文章

Line搜尋「@CSScoke」加入CSS可樂公開帳號,可以收到 Amos 第一手資訊喔
CSS 可樂部落格
CSS coke 的 Youtube 直播頻道
快按此訂閱 CSS coke 的頻道接收最新教學
/images/emoticon/emoticon12.gif


上一篇
CSS 組合式宣告 - 新手開發從這裡開始進步
下一篇
CSS 通用選取器 - 一個你我都該熟知的老朋友
系列文
金魚都能懂的 CSS 選取器 - 金魚都能懂了你還怕學不會嗎30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

5
huli
iT邦新手 3 級 ‧ 2019-09-22 15:52:26

對於 CSS selector 效能的那邊,最常見的參考資料應該是這個 2011 年由 Mozilla 工程師所做出的回答:Why do browsers match CSS selectors from right to left?

然後在早期 Google 或是 Mozilla 的文件也都有寫到這件事情,可以參考這篇在 Stackoverflow 上的備份:CSS combinator precedence?

不過裡面提到的文章現在都找不到了,也有人跟我一樣感到疑惑,所以問了這個問題:What happened to the “Use efficient CSS selectors” rule?,底下有人貼了一篇:CSS Selector Performance has changed! (For the better),內容大意是說 webkit 對 CSS selector 做了一系列的優化,所以開發者不必擔心如何自己優化,那應該是引擎的事。也有把幾個優化給寫出來。

Mozilla 在 2017 年發表的文章 Inside a super fast CSS engine: Quantum CSS (aka Stylo) 有提到 CSS engine 的工作流程,但也沒有明確提到從右比對到左這件事,但還是滿值得一看的文章就是了。

總結一下,基本上能找到的參考資料都已經是 8 年前的文章了,然後看起來瀏覽器有對 CSS selector 做過優化,所以儘管寫了一長串的選擇器,對效能的影響應該也不太大。不過實際上的差距應該還是要測一下才會知道啦。

CSScoke iT邦新手 3 級 ‧ 2019-09-22 18:04:27 檢舉

感謝胡立大大回覆與資料支援 ^^
最近在研究瀏覽器運作原理,等研究完再來分享一些心得^^

huli iT邦新手 3 級 ‧ 2019-09-22 19:40:38 檢舉

被大大叫大大好不習慣XDDD

今天發現另一篇鐵人賽文章也有講到類似的東西,參考資料裡面有附上相關原始碼:05. [CSS] 元素選取器是如何運作的?,也可以參考看看。

期待之後瀏覽器運作原理的相關心得~

0
阿展展展
iT邦好手 1 級 ‧ 2019-12-04 09:27:31

世界奇觀的層數/images/emoticon/emoticon46.gif

我要留言

立即登入留言