在前端的面試中,有一道很廣泛的題目,就是CSS選擇器的優先級。原來週一以爲這個東西好像蠻簡單的,就是認知裏面的類選擇器、id選擇器和標籤,而後就沒了。可是卻不知不少時候咱們都輸給了「我覺得」,事實證實一切內容並無想象中的那麼簡單。javascript
當我看完書的時候,才發現優先級須要經過計算來肯定,而後呢,還有通配選擇器、選擇符和邏輯組合僞類等等各類類型的計算。css
在沒有看書以前,我對這些內容的想法多是這樣的:html
所以,寫下這篇文章,總結關於 CSS
選擇器中的優先級。一塊兒來學習⑧~💡前端
在開始講解本文以前,咱們先用一張思惟導圖來了解本文的結構內容。詳情見下圖👇java
接下來開始進入本文的講解~web
CSS
倒是爲樣式服務的,它重表現,輕邏輯,如同人的思想同樣,相互碰撞才能產生火花。CSS
選擇器來講,它做爲 CSS
世界的支柱,其做用比如人類的脊柱,與 HTML
結構、瀏覽器行爲、用戶行爲以及整個 CSS
世界相互依存、相互做用,這必然會產生不少碰撞,使得 CSS
選擇器變得很是強悍。CSS選擇器能夠分爲4類,即選擇器、選擇符、僞類和僞元素。下面介紹這四種類型的區別。面試
選擇器,指的是咱們日常使用的 css
聲明塊前面的標籤、類名等等。好比:編程
body{
background: #333;
}
複製代碼
以上代碼中的 body
就是一種選擇器,是類型選擇器,也能夠稱爲標籤選擇器。瀏覽器
再好比:markdown
.container{
background-color: #fff;
}
複製代碼
以上代碼中的 .container
也是選擇器,屬於屬性選擇器中的一種,咱們也常常稱它爲類選擇器。
CSS
中有5種選擇符,分別爲:
選擇符 | 定義 |
---|---|
空格( ) | 表示後代關係 |
尖括號(>) | 表示父子關係 |
加號(+) | 表示相鄰兄弟關係 |
波浪號(~) | 表示兄弟關係 |
雙管道(||) | 表示列關係 |
咱們來舉些例子,更好的理解這幾種選擇符。具體代碼以下:
/* 後代關係 */
.container img {
object-fit: contain;
}
/* 父子關係 */
ol > li {
margin: 0 auto;
}
/* 相鄰兄弟關係 */
button + p {
margin-right: 10px;
}
/* 兄弟關係 */
button ~ p {
margin-left: 10px;
}
/* 列 */
.col || td {
background-color: gray;
}
複製代碼
這裏須要注意的是,相鄰兄弟關係和兄弟關係的區別,這兩個看起來很類似,很容易混淆。
對於 +
的相鄰關係,指的是當前的 button
以及在它同一層級上的下一個元素 p
的樣式;而對於 ~
來講,就是當前 button
以及在它同一層級上的全部 p
元素的樣式。
能夠說 +
號是一對一關係,而 ~
則是一對多關係。
僞類的特徵是其前面會有一個冒號 :
。對於僞類來講,它一般與瀏覽器行爲和用戶行爲相關聯,能夠把它當作是 css
世界中的 javascript
。好比:
a:hover{
color: gray;
}
複製代碼
僞元素的特徵是其前面會有兩個冒號 ::
,常見的有 ::before
、 ::after
、 ::first-letter
和 ::first-line
等。
CSS
選擇器中還有一個命名空間的概念。所謂命名空間,就是咱們日常所看到的 @namespace
,主要做用是用來避免衝突。
好比說,咱們在 html
和 svg
中都會用到 <a>
連接,這個時候就極可能會發生衝突。那問題來了,衝突製造了,又該怎麼解決呢?這個時候就能夠用剛剛提到的命名空間 @namespace
來解決。
咱們來看一段代碼,更直觀的瞭解命名空間。具體代碼以下:
<p>
這是文字:
<a>點擊刷新</a>
</p>
<p>
這是SVG:
<svg>
<a xlink:href>
<path d="M433.109 23.694c...2.706z"/>
</a>
</svg>
</p>
@namespace url(http://w3.org/1999/xhtml);
@namespace svg url(http://www.w3.org/2000/svg);
/* 管道符 */
svg|a {
color: black;
fill: currentColor;
}
/* 標籤選擇器 */
a {
color: gray;
}
複製代碼
你們能夠看到, svg|a
中有一個管道符 |
,那麼管道符前面的字符表示的就是命名空間的代稱,而管道符後面的內容則是選擇器。這段代碼最終的顯示效果是這樣的:
若是按照咱們預約的,可能有的小夥伴以爲樣式不是越靠後優先級越高嗎,而爲何 svg
中的 a
仍是顯示了黑色,而不是灰色呢?
其實,你們能夠看到上面的命名空間,上述代碼中就表示了,在 http://www.w3.org/2000/svg
這個命名空間下全部 <a>
的顏色都是黑色 black
,且因爲 xhtml
的命名空間(你們定位到第一個命名空間)也被指定了。所以呢, svg
中的 <a>
標籤也就不會受到 標籤選擇器a
的影響,即使 純標籤選擇器a
的優先級再高,那也是無效的。
講到這個,咱們來對 css選擇器命名空間
作個小結:
其實, css選擇器命名空間
的兼容性很好,至少類似10年前瀏覽器就支持了。可是呢,確不多有人在項目中去使用它。這是爲何呢?
緣由主要有如下兩點:
在 html
中直接內聯 svg
的應用場景相對來講仍是比較少的,你能夠試想一下,咱們日常在引用阿里圖標的時候,會直接把svg那一大串資源,給本身引入到本身的頁面中嗎?應該沒有人這麼幹吧。因此,它更多的是做爲獨立資源來使用。
還有一個緣由就是,有它更好的替代方案。好比:
svg a{
color: black;
}
複製代碼
這樣作的惟一缺點就是,增長了 svg
中 a
元素的優先級。可是再大多數的狀況下,對咱們的開發基本上沒什麼影響。
因此呢,對於 css
選擇器的命名空間,你們能夠選擇瞭解便可,至少在遇到大規模衝突場景下,給本身多一個解決方法~
幾乎全部的 css
樣式衝突、樣式覆蓋等等問題,都跟 css
聲明的優先級錯位脫不開關係。接下來,咱們將從 css
優先級規則以及優先級的計算爲切入點,來了解關於 css
選擇器的優先級。
css
優先級有着明顯的不可逾越的等級制度,所以,咱們能夠將其劃分爲 0~5 這 6 個等級。其中,前4個等級由 css選擇器
決定,後2個等級由 書寫形式
和 特定語法
決定。 下面來了解這6種等級制度各自的區別,具體以下表:
等級 | 定義 | 計算值 |
---|---|---|
0級 | 通配選擇器、選擇符和邏輯組合僞類 | 0 |
1級 | 標籤選擇器 | 1 |
2級 | 類選擇器、屬性選擇器和僞類 | 10 |
3級 | ID選擇器 | 100 |
4級 | style屬性內聯 | 1000 |
5級 | !important | 10000 |
繼續,咱們對這6個級別對應的選擇器樣式來作個簡單的瞭解。具體以下:
0級:通配選擇器、選擇符和邏輯組合僞類
/* 通配選擇器指星號(*) */
* {
color: #fff;
}
/* ------------------分割線------------------- */
/* 選擇符指+、>、~、空格和|| 具體上面有作詳細說明,再也不細述 */
.container img {
/* 後代關係 */
}
ol > li {
/* 父子關係 */
}
button + p {
/* 相鄰兄弟關係 */
}
button ~ p {
/* 兄弟關係 */
}
.col || td {
/* 列 */
}
/* ------------------分割線------------------- */
/* 邏輯組合僞類有:not()、:is()和:where() 須要注意的是,只有邏輯組合僞類的優先級是0,其餘僞類的優先級並非這樣的 */
:not() {
color: #fff;
}
複製代碼
1級:標籤選擇器
/* 標籤選擇器相似於body,p,span,div等等這些標籤元素 */
body {
color: #333;
}
複製代碼
2級:類選擇器、屬性選擇器和僞類
/* 類選擇器指class */
.container {
color: #666;
}
/* ------------------分割線------------------- */
/* 屬性選擇器指指針對某個標籤裏面的屬性進行特定標識 好比如下,表示只對有 href 屬性的錨(a 元素)應用樣式 */
a[href] {
color:#666;
}
/* ------------------分割線------------------- */
/* 僞類指:hover等 */
a:hover {
color: #666;
}
複製代碼
3級:ID選擇器
#container {
color: #999;
}
複製代碼
4級:style屬性內聯
<span style="color: #ccc;">
優先級
</span>
複製代碼
5級:! important
/* !important是頂級優先級, 能夠重置 js 設置的樣式, 惟一推薦使用的場景就是使 js 設置無效(切勿濫用)*/
#container {
color: #999 !important;
}
複製代碼
上面咱們瞭解到了關於 css
選擇器的各類玩法,那下面咱們就來看一下它是怎麼玩的。
咱們用一個表格來羅列處常見的一些計算。固然,你們也能夠拿起小本本邊看邊進行計算。具體以下表:
選擇器 | 計算值 | 計算細則 |
---|---|---|
*{ } | 0 | 1個0級通配選擇器,優先級數值計算結果爲0 |
p { } | 1 | 1個1級通配選擇器,計算結果爲1 |
ul > li { } | 2 | 2個1級標籤選擇器,1個0級選擇符,計算結果爲1+0+1 |
li > ol + ol { } | 3 | 3個1級標籤選擇器,2個0級選擇符,計算結果爲1+0+1+0+1 |
.foo { } | 10 | 1個2級類名選擇器,計算結果爲10 |
a:not([rel=nofollow]) { } | 11 | 1個標籤選擇器,1個0級否認僞類,1個2級屬性選擇器,計算結果爲1+0+10 |
a:hover { } | 11 | 1個1級標籤選擇器,1個2級僞類,計算結果爲1+10 |
ol li.foo { } | 12 | 2個1級標籤選擇器,1個2級類名選擇器,1個0級空格選擇符,計算結果爲1+0+1+10 |
li.foo.bar { } | 21 | 1個1級標籤選擇器,2個2級類名選擇器,計算結果爲1+10+10 |
#foo { } | 100 | 1個3級id選擇器,計算結果爲100 |
#foo .bar p { } | 111 | 1個3級id選擇器,1個2級類名選擇器,1個1級標籤選擇器,2個0級空格選擇器,計算結果爲100+10+1+0+0 |
還有一種可能會出現的狀況就是,遇到計算結果相同的,咱們該如何取值呢?好比:
<html lang=「zh-CN」>
<body class="foo">顏色是</body>
</html>
<style> body.foo:not([dir]) { color: red; } html[lang] > .foo { color: blue; } </style>
複製代碼
咱們來分析下以上這段代碼。首先,第一段 css
代碼中,出現1個標籤選擇器 body
,1個類名選擇器 .foo
和1個否認僞類 :not
,以及1個屬性選擇器 [dir]
。所以計算結果爲 1+10+0+10
,也就是 21
。
咱們再來分析第二段代碼, html[lang] > .foo
中出現1個標籤選擇器 html
,1個屬性選擇器 [lang]
,1個類名選擇器 .foo
,這裏 0級選擇器
忽略不計。所以,最終計算結果爲 1+10+10=21
。
因此,你們能夠看到,兩個最終的計算結果都是 21
。那咱們到底用哪一個樣式呢?
印證標題所說的,遵循**「後來居上」原則**, 最終這段代碼顯示爲藍色。
在實際開發中,咱們不免會遇到須要增長 css
選擇器優先級的場景。卻不知不少小夥伴可能直接就把內聯和 !important
直接懟上去了,這樣子形成的後果可能有點恐怖了。
因此,咱們須要來了解幾種增長選擇器權重的作法。具體以下:
假設如今我要給下面這段代碼增長權重,例如:
.foo {
color: #333;
}
複製代碼
不少時候咱們的作法多是增長嵌套或者是增長一個標籤選擇器,例如:
/* 增長嵌套 */
.father .foo {
}
/* 增長標籤選擇器 */
div.foo {
}
複製代碼
可是這種作法每每不是最好的,由於它會增長了代碼的耦合度,下降代碼的可維護性。試想一下,一旦類名變了,或者標籤換了,那你的樣式豈不是就要往回去改了,這樣會不會就有點不太友好了。
因此,咱們引出一下兩種方式,來解決這個問題。具體以下:
第一種: 重複選擇器自身
.foo.foo {
}
複製代碼
第二種: 藉助已存在的屬性選擇器
.foo[class] {
}
#foo[id] {
}
複製代碼
這樣看起來,會不會就友好了許多呢。
在上文中,咱們講到關於 css
選擇器的一些基礎知識,以及 css
選擇器的優先級的各類計算方式,還有關於「後來居上」原則和一些提高優先級的小tips。
講到這裏,關於 css
選擇器優先級的講解就結束啦!但願對你們有幫助~
position和z-index👉你可能對position和z-index有一些誤解
書籍👉張鑫旭老師的《CSS選擇器世界》
- 關注公衆號星期一研究室,第一時間關注優質文章,更多精選專欄待你解鎖~
- 若是這篇文章對你有用,記得留個腳印jio再走哦~
- 以上就是本文的所有內容!咱們下期見!👋👋👋