誰動了個人選擇器?深刻理解CSS選擇器優先級

😏序言

在前端的面試中,有一道很廣泛的題目,就是CSS選擇器的優先級。原來週一以爲這個東西好像蠻簡單的,就是認知裏面的類選擇器、id選擇器和標籤,而後就沒了。可是卻不知不少時候咱們都輸給了「我覺得」,事實證實一切內容並無想象中的那麼簡單。javascript

當我看完書的時候,才發現優先級須要經過計算來肯定,而後呢,還有通配選擇器、選擇符和邏輯組合僞類等等各類類型的計算。css

在沒有看書以前,我對這些內容的想法多是這樣的:html

懵

所以,寫下這篇文章,總結關於 CSS 選擇器中的優先級。一塊兒來學習⑧~💡前端

🧐文章內容搶先看

在開始講解本文以前,咱們先用一張思惟導圖來了解本文的結構內容。詳情見下圖👇java

思惟導圖

接下來開始進入本文的講解~web

🤐1、基礎知識

一、爲何CSS選擇器很強

  • 傳統編程語言講求邏輯清晰,井井有條,而且主要爲功能服務。
  • CSS 倒是爲樣式服務的,它重表現輕邏輯,如同人的思想同樣,相互碰撞才能產生火花。
  • 對於 CSS 選擇器來講,它做爲 CSS 世界的支柱,其做用比如人類的脊柱,與 HTML 結構、瀏覽器行爲、用戶行爲以及整個 CSS 世界相互依存、相互做用,這必然會產生不少碰撞,使得 CSS 選擇器變得很是強悍。

二、CSS選擇器的一些基本概念

(1)4種基本概念

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 等。

(2)CSS選擇器的命名空間

CSS 選擇器中還有一個命名空間的概念。所謂命名空間,就是咱們日常所看到的 @namespace ,主要做用是用來避免衝突

好比說,咱們在 htmlsvg 中都會用到 <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;
    }
    複製代碼

    這樣作的惟一缺點就是,增長了 svga 元素的優先級。可是再大多數的狀況下,對咱們的開發基本上沒什麼影響。

因此呢,對於 css 選擇器的命名空間,你們能夠選擇瞭解便可,至少在遇到大規模衝突場景下,給本身多一個解決方法~

😲2、CSS選擇器的優先級

幾乎全部的 css 樣式衝突、樣式覆蓋等等問題,都跟 css 聲明的優先級錯位脫不開關係。接下來,咱們將從 css 優先級規則以及優先級的計算爲切入點,來了解關於 css 選擇器的優先級。

一、優先級規則概覽

(1)選擇器權重

css 優先級有着明顯的不可逾越的等級制度,所以,咱們能夠將其劃分爲 0~56 個等級。其中,前4個等級由 css選擇器 決定,後2個等級由 書寫形式特定語法 決定。 下面來了解這6種等級制度各自的區別,具體以下表:

等級 定義 計算值
0級 通配選擇器、選擇符和邏輯組合僞類 0
1級 標籤選擇器 1
2級 類選擇器、屬性選擇器和僞類 10
3級 ID選擇器 100
4級 style屬性內聯 1000
5級 !important 10000

(2)選擇器說明

繼續,咱們對這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 選擇器的各類玩法,那下面咱們就來看一下它是怎麼玩的。

(1)選擇器優先級計算

咱們用一個表格來羅列處常見的一些計算。固然,你們也能夠拿起小本本邊看邊進行計算。具體以下表:

選擇器 計算值 計算細則
*{ } 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

(2)「後來居上」原則

還有一種可能會出現的狀況就是,遇到計算結果相同的,咱們該如何取值呢?好比:

<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 。那咱們到底用哪一個樣式呢?

印證標題所說的,遵循**「後來居上」原則**, 最終這段代碼顯示爲藍色。

(3)提高優先級的小技巧

在實際開發中,咱們不免會遇到須要增長 css 選擇器優先級的場景。卻不知不少小夥伴可能直接就把內聯和 !important 直接懟上去了,這樣子形成的後果可能有點恐怖了。

因此,咱們須要來了解幾種增長選擇器權重的作法。具體以下:

假設如今我要給下面這段代碼增長權重例如:

.foo {
	color: #333;
}
複製代碼

不少時候咱們的作法多是增長嵌套或者是增長一個標籤選擇器例如:

/* 增長嵌套 */
.father .foo {

}

/* 增長標籤選擇器 */
div.foo {

}
複製代碼

可是這種作法每每不是最好的,由於它會增長了代碼的耦合度,下降代碼的可維護性。試想一下,一旦類名變了,或者標籤換了,那你的樣式豈不是就要往回去改了,這樣會不會就有點不太友好了。


因此,咱們引出一下兩種方式,來解決這個問題。具體以下:

第一種: 重複選擇器自身

.foo.foo {
	
}
複製代碼

第二種: 藉助已存在的屬性選擇器

.foo[class] {

}

#foo[id] {

}
複製代碼

這樣看起來,會不會就友好了許多呢。

🥳3、結束語

在上文中,咱們講到關於 css 選擇器的一些基礎知識,以及 css 選擇器的優先級的各類計算方式,還有關於「後來居上」原則和一些提高優先級的小tips。

講到這裏,關於 css 選擇器優先級的講解就結束啦!但願對你們有幫助~

🐣彩蛋 One More Thing

🏷️往期推薦&參考資料

position和z-index👉你可能對position和z-index有一些誤解

書籍👉張鑫旭老師的《CSS選擇器世界》

🏷️番外篇

  • 關注公衆號星期一研究室,第一時間關注優質文章,更多精選專欄待你解鎖~
  • 若是這篇文章對你有用,記得留個腳印jio再走哦~
  • 以上就是本文的所有內容!咱們下期見!👋👋👋
相關文章
相關標籤/搜索