梳理選擇器的種類,理解選擇器的優先順序,從而避免莫名其妙的樣式重疊問題。
一、選擇器的種類
1、基本選擇器
基本選擇器包含:通配選擇器、元素選擇器、ID選擇器、類選擇器和群組選擇器。
對於類選擇器的命名,`-`和`_`兩者多有,具體可以看這裡
通配選擇器(*),它用來選擇所有元素,不過這個選擇器的效率比較低,所以慎重選擇,但是瞅了一眼Boostrap4.0是這樣設定box-sizing:
html {
box-sizing: border-box;
}
*, *::before, *::after {
box-sizing: inherit;
}
複製程式碼
所以吧,也不是不能用,不過也就這一處,還是得少用。
ID選擇器,它的唯一性是規範,但是應用於多個元素,樣式同樣生效,不推薦這樣做。
群組選擇器,通過逗號隔開,可以有效的減少一些冗餘程式碼,例如上面的例子中:
*, *::before, *::after {
box-sizing: inherit;
}
複製程式碼
2、屬性選擇器
屬性選擇器主要針對於元素的屬性值進行篩選,包含這幾種操作符:=、|=、~=、*=、^=和$=:
- [attr=val]:屬性值為val;
- [attr|=val]:屬性值為val或者以val-開頭;
- [attr~=val]:屬性值為val或者以多個空格分開含有val;
- [attr*=val]:屬性值包含val;
- [attr^=val]:屬性值以val開頭;
- [attr$=val]:屬性值以val結尾。
屬性選擇器的應用很多,例如Vue中的scoped css也正是利用屬性選擇器實現的。
3、層次選擇器
層次選擇器包含後代選擇器(E F)、子選擇器(E > F)、相鄰兄弟選擇器(E + F)和通用選擇器(E ~ F)。
後代選擇器與子選擇器的區別:相比較前者,子選擇器的搜尋範圍侷限於兒子節點。
相鄰兄弟選擇器,選擇E後面相鄰的兄弟節點F。很遺憾不能選擇前面的。這個選擇器的應用也很多,比如我們設定列表項之間的距離為20px:
li:not(:last-child) + li {
margin-top: 20px;
}
複製程式碼
通用選擇器,選擇E後面所有的兄弟節點F。同樣上面的例子:
li:first-child ~ li {
margin-top: 20px;
}
複製程式碼
如果你能理解上面這兩種寫法,基本上這兩個選擇器你就理解了。
4、偽元素選擇器
首先對於偽元素的寫法,標準是推薦雙冒號,感覺這樣寫挺好的,可以和偽類區別開來。
::first-letter作用於整塊文字的第一段的第一個文字,元素必須為塊級元素。例如修飾段落第一個單詞的樣式:
p::first-letter {
color: red;
font-size: 20px;
}
複製程式碼
::first-line則是作用於整塊文字的第一段,同樣必須為塊級元素。
::before和::after分別向元素的前後新增內容,用處很大,比如我們實現這樣的購物車:
<span role="btn" aria-label="購物車" attr-quantity="2" class="caricon"></span>
複製程式碼
/* 這裡就不展現無關緊要的樣式了 */
.caricon {
/* 這裡設定容器的樣式 */
}
.caricon::before {
/* 通過偽元素設定購物車圖示 */
}
.caricon::after {
/*
這兩個偽元素多有一個重要的content屬性,用來設定偽元素的內容
這裡通過attr獲取元素的屬性值,實現購物車數量
*/
content: attr(attr-quantity);
}
複製程式碼
在一些網站中,當你滑鼠選擇文字會發生樣式變化,這是因為用了::selection,不過它能改變的CSS屬性比較有限,具體可以查詢MDN。
還有我們討厭input的placeholder樣式太丑時,你可以使用::placeholder來修改,但是這是一個試驗性的偽元素,還有很多試驗性的偽元素,有興趣可以搜尋一下。
5、偽類
偽類的組成就更豐富了,這裡選擇兩個比較重要可能還有點容易混淆的說說。
首先看看否定偽類選擇器:not,在前面的例子中你已經看到它的身影了,它匹配不符合描述的元素,用處可以說很大。
然後就是結構偽類選擇器,這裡的內容也多,而且很容易混淆。
例如:first-child和:first-of-type:
p:first-child {
/* 計算範圍:所有的兄弟節點 */
}
p:first-of-type {
/* 計算範圍:兄弟節點中所有p元素 */
}
複製程式碼
同樣還有:last-child和:last-of-type,就很容易懂了。
:nth-child就比較強大了,不僅可以使用odd和even,還可以使用表示式。例如我們列表的斑馬線:
li:nth-child(even) {
background: red;
}
複製程式碼
關於:nth-child重要的幾點可以總結為:
- 值的下標是從1開始的;
- 但是n的下標是從0開始;
- 當表示式的值為0或者負數是無效的;
- 採用表示式可以實現很多需求,例如我只想讓列表的前三項設定樣式:nth-child(-n + 3);
像什麼:nth-of-type,:nth-last-child和:nth-last-of-type是不是小case了。
:only-child表示父節點只有一個子節點,其實學習了上面的一些選擇器,我們完全可以找到等價的表達方式:
li:first-child:last-child {
background: yellow;
}
複製程式碼
當然還有:only-of-type是必不可少的。
二、選擇器的優先順序
上面這麼多的選擇器,是不是很頭大,這也是為什麼這裡要特地說一下選擇器優先順序。當多條樣式應用在一個元素上,系統會將樣式合併,當一個屬性被賦了多次值,到底取哪個值呢?這時候就需要優先順序了,優先順序高的覆蓋優先順序低的。
選擇器優先順序規則:
- 首先萬用字元是沒有權重的(所以我感覺這點也是不推薦使用它的原因);
- !important的權重bug級的高;
- 權重第二高的就是元素的行內樣式(style屬性中的值);
接下來的情況我們可以數值化:
- id選擇器的權重為100;
- 類選擇器、屬性選擇器和偽類選擇器的權重為10;
- 元素和偽元素的權重為1。
- 如果優先順序一樣,則後宣告的優先順序高。
看個例子:
li {
width: 300px;
height: 90px;
background: red;
}
ul li {
background: yellow;
}
複製程式碼
首先對於沒有重複賦值的width和height,並不存在什麼優先順序的問題,而對於background,第一個樣式的優先順序為1,而第二個樣式的優先順序為2,所以將yellow賦值給background。
三、總結
前面寫了很多廢話,也沒有將選擇器羅列完整,但是基本的構成,大家應該很清晰了。
對於後面說的選擇器優先順序的計算,並不是說你每次寫完樣式多要求算一下,最重要的目的是:你理解計算規則後,讓你對每種選擇器的應用場景更加清晰,而不是說隨便用,從而造成意想不到的樣式覆蓋問題。
最後,謝謝大家看完這篇文章。
參考資料:
圖解CSS3
CSS Specificity: Things You Should Know
喜歡本文的小夥伴們,歡迎關注我的訂閱號超愛敲程式碼,檢視更多內容.