谁动了我的选择器?深入理解CSS选择器优先级
深入理解CSS選擇器優(yōu)先級(jí)
- 😏序言
- 🧐文章內(nèi)容搶先看
- 🤐一、基礎(chǔ)知識(shí)
- 1、為什么CSS選擇器很強(qiáng)
- 2、CSS選擇器的一些基本概念
- (1)4種基本概念
- Ⅰ. 選擇器
- Ⅱ. 選擇符
- Ⅲ. 偽類(lèi)
- Ⅳ. 偽元素
- (2)CSS選擇器的命名空間
- 😲二、CSS選擇器的優(yōu)先級(jí)
- 1、優(yōu)先級(jí)規(guī)則概覽
- (1)選擇器優(yōu)先級(jí)
- (2)選擇器說(shuō)明
- 2、優(yōu)先級(jí)計(jì)算
- (1)選擇器優(yōu)先級(jí)計(jì)算
- (2)“后來(lái)居上”原則
- (3)提升優(yōu)先級(jí)的小技巧
- 🥳三、結(jié)束語(yǔ)
- 🐣彩蛋 One More Thing
- 🏷?往期推薦&參考資料
- 🏷?番外篇
😏序言
在前端的面試中,有一道很普遍的題目,就是CSS選擇器的優(yōu)先級(jí)。原來(lái)周一覺(jué)得這個(gè)東西好像蠻簡(jiǎn)單的,就是認(rèn)知里面的類(lèi)選擇器、id選擇器和標(biāo)簽,然后就沒(méi)了。但是殊不知很多時(shí)候我們都輸給了“我以為”,事實(shí)證明一切內(nèi)容并沒(méi)有想象中的那么簡(jiǎn)單。
當(dāng)我看完書(shū)的時(shí)候,才發(fā)現(xiàn)優(yōu)先級(jí)需要通過(guò)計(jì)算來(lái)確定,然后呢,還有通配選擇器、選擇符和邏輯組合偽類(lèi)等等各種類(lèi)型的計(jì)算。
在沒(méi)有看書(shū)之前,我對(duì)這些內(nèi)容的想法可能是這樣的:
因此,寫(xiě)下這篇文章,總結(jié)關(guān)于 CSS 選擇器中的優(yōu)先級(jí)。一起來(lái)學(xué)習(xí)⑧~💡
🧐文章內(nèi)容搶先看
在開(kāi)始講解本文之前,我們先用一張思維導(dǎo)圖來(lái)了解本文的結(jié)構(gòu)內(nèi)容。詳情見(jiàn)下圖👇
接下來(lái)開(kāi)始進(jìn)入本文的講解~
🤐一、基礎(chǔ)知識(shí)
1、為什么CSS選擇器很強(qiáng)
- 傳統(tǒng)編程語(yǔ)言講求邏輯清晰,層次分明,并且主要為功能服務(wù)。
- 但 CSS 卻是為樣式服務(wù)的,它重表現(xiàn),輕邏輯,如同人的思想一樣,相互碰撞才能產(chǎn)生火花。
- 對(duì)于 CSS 選擇器來(lái)說(shuō),它作為 CSS 世界的支柱,其作用好比人類(lèi)的脊柱,與 HTML 結(jié)構(gòu)、瀏覽器行為、用戶(hù)行為以及整個(gè) CSS 世界相互依存、相互作用,這必然會(huì)產(chǎn)生很多碰撞,使得 CSS 選擇器變得非常強(qiáng)悍。
2、CSS選擇器的一些基本概念
(1)4種基本概念
CSS選擇器可以分為4類(lèi),即選擇器、選擇符、偽類(lèi)和偽元素。下面介紹這四種類(lèi)型的區(qū)別。
Ⅰ. 選擇器
選擇器,指的是我們平常使用的 css 聲明塊前面的標(biāo)簽、類(lèi)名等等。比如:
body{background: #333; }以上代碼中的 body 就是一種選擇器,是類(lèi)型選擇器,也可以稱(chēng)為標(biāo)簽選擇器。
再比如:
.container{background-color: #fff; }以上代碼中的 .container 也是選擇器,屬于屬性選擇器中的一種,我們也經(jīng)常稱(chēng)它為類(lèi)選擇器。
Ⅱ. 選擇符
CSS 中有5種選擇符,分別為:
| 空格( ) | 表示后代關(guān)系 |
| 尖括號(hào)(>) | 表示父子關(guān)系 |
| 加號(hào)(+) | 表示相鄰兄弟關(guān)系 |
| 波浪號(hào)(~) | 表示兄弟關(guān)系 |
| 雙管道(||) | 表示列關(guān)系 |
我們來(lái)舉些例子,更好的理解這幾種選擇符。具體代碼如下:
/* 后代關(guān)系 */ .container img {object-fit: contain; }/* 父子關(guān)系 */ ol > li {margin: 0 auto; }/* 相鄰兄弟關(guān)系 */ button + p {margin-right: 10px; }/* 兄弟關(guān)系 */ button ~ p {margin-left: 10px; }/* 列 */ .col || td {background-color: gray; }這里需要注意的是,相鄰兄弟關(guān)系和兄弟關(guān)系的區(qū)別,這兩個(gè)看起來(lái)很相似,很容易混淆。
對(duì)于 + 的相鄰關(guān)系,指的是當(dāng)前的 button 以及在它同一層級(jí)上的下一個(gè)元素 p 的樣式;而對(duì)于 ~ 來(lái)說(shuō),就是當(dāng)前 button 以及在它同一層級(jí)上的所有 p 元素的樣式。
可以說(shuō) + 號(hào)是一對(duì)一關(guān)系,而 ~ 則是一對(duì)多關(guān)系。
Ⅲ. 偽類(lèi)
偽類(lèi)的特征是其前面會(huì)有一個(gè)冒號(hào) : 。對(duì)于偽類(lèi)來(lái)說(shuō),它通常與瀏覽器行為和用戶(hù)行為相關(guān)聯(lián),可以把它看成是 css 世界中的 javascript 。比如:
a:hover{color: gray; }Ⅳ. 偽元素
偽元素的特征是其前面會(huì)有兩個(gè)冒號(hào) :: ,常見(jiàn)的有 ::before 、 ::after 、 ::first-letter 和 ::first-line 等。
(2)CSS選擇器的命名空間
CSS 選擇器中還有一個(gè)命名空間的概念。所謂命名空間,就是我們平常所看到的 @namespace ,主要作用是用來(lái)避免沖突。
比如說(shuō),我們?cè)?html 和 svg 中都會(huì)用到 <a> 鏈接,這個(gè)時(shí)候就很可能會(huì)發(fā)生沖突。那問(wèn)題來(lái)了,沖突制造了,又該怎么解決呢?這個(gè)時(shí)候就可以用剛剛提到的命名空間 @namespace 來(lái)解決。
我們來(lái)看一段代碼,更直觀的了解命名空間。具體代碼如下:
<p>這是文字:<a>點(diǎn)擊刷新</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; } /* 標(biāo)簽選擇器 */ a {color: gray; }大家可以看到, svg|a 中有一個(gè)管道符 | ,那么管道符前面的字符表示的就是命名空間的代稱(chēng),而管道符后面的內(nèi)容則是選擇器。這段代碼最終的顯示效果是這樣的:
如果按照我們預(yù)定的,可能有的小伙伴覺(jué)得樣式不是越靠后優(yōu)先級(jí)越高嗎,而為什么 svg 中的 a 還是顯示了黑色,而不是灰色呢?
其實(shí),大家可以看到上面的命名空間,上述代碼中就表示了,在 http://www.w3.org/2000/svg 這個(gè)命名空間下所有 <a> 的顏色都是黑色 black ,且由于 xhtml 的命名空間(大家定位到第一個(gè)命名空間)也被指定了。因此呢, svg 中的 <a> 標(biāo)簽也就不會(huì)受到 標(biāo)簽選擇器a 的影響,即便 純標(biāo)簽選擇器a 的優(yōu)先級(jí)再高,那也是無(wú)效的。
講到這個(gè),我們來(lái)對(duì) css選擇器命名空間 做個(gè)小結(jié):
其實(shí), css選擇器命名空間 的兼容性很好,至少相似10年前瀏覽器就支持了。但是呢,確很少有人在項(xiàng)目中去使用它。這是為什么呢?
原因主要有以下兩點(diǎn):
-
在 html 中直接內(nèi)聯(lián) svg 的應(yīng)用場(chǎng)景相對(duì)來(lái)說(shuō)還是比較少的,你可以試想一下,我們平常在引用阿里圖標(biāo)的時(shí)候,會(huì)直接把svg那一大串資源,給自己引入到自己的頁(yè)面中嗎?應(yīng)該沒(méi)有人這么干吧。所以,它更多的是作為獨(dú)立資源來(lái)使用。
-
還有一個(gè)原因就是,有它更好的替代方案。比如:
svg a{color: black; }這樣做的唯一缺點(diǎn)就是,增加了 svg 中 a 元素的優(yōu)先級(jí)。但是再大多數(shù)的情況下,對(duì)我們的開(kāi)發(fā)基本上沒(méi)什么影響。
所以呢,對(duì)于 css 選擇器的命名空間,大家可以選擇了解即可,至少在遇到大規(guī)模沖突場(chǎng)景下,給自己多一個(gè)解決方法~
😲二、CSS選擇器的優(yōu)先級(jí)
幾乎所有的 css 樣式?jīng)_突、樣式覆蓋等等問(wèn)題,都跟 css 聲明的優(yōu)先級(jí)錯(cuò)位脫不開(kāi)關(guān)系。接下來(lái),我們將從 css 優(yōu)先級(jí)規(guī)則以及優(yōu)先級(jí)的計(jì)算為切入點(diǎn),來(lái)了解關(guān)于 css 選擇器的優(yōu)先級(jí)。
1、優(yōu)先級(jí)規(guī)則概覽
(1)選擇器優(yōu)先級(jí)
css 優(yōu)先級(jí)有著明顯的不可逾越的等級(jí)制度,因此,我們可以將其劃分為 0~5 這 6 個(gè)等級(jí)。其中,前4個(gè)等級(jí)由 css選擇器 決定,后2個(gè)等級(jí)由 書(shū)寫(xiě)形式 和 特定語(yǔ)法 決定。 下面來(lái)了解這6種等級(jí)制度各自的區(qū)別,具體如下表:
| 0級(jí) | 通配選擇器、選擇符和邏輯組合偽類(lèi) | 0 |
| 1級(jí) | 標(biāo)簽選擇器 | 1 |
| 2級(jí) | 類(lèi)選擇器、屬性選擇器和偽類(lèi) | 10 |
| 3級(jí) | ID選擇器 | 100 |
| 4級(jí) | style屬性?xún)?nèi)聯(lián) | 1000 |
| 5級(jí) | !important | 10000 |
(2)選擇器說(shuō)明
繼續(xù),我們對(duì)這6個(gè)級(jí)別對(duì)應(yīng)的選擇器樣式來(lái)做個(gè)簡(jiǎn)單的了解。具體如下:
0級(jí):通配選擇器、選擇符和邏輯組合偽類(lèi)
/* 通配選擇器指星號(hào)(*) */ * {color: #fff; }/* ------------------分割線------------------- *//* 選擇符指+、>、~、空格和|| 具體上面有做詳細(xì)說(shuō)明,不再細(xì)述 */ .container img {/* 后代關(guān)系 */ }ol > li {/* 父子關(guān)系 */ }button + p {/* 相鄰兄弟關(guān)系 */ }button ~ p {/* 兄弟關(guān)系 */ }.col || td {/* 列 */ }/* ------------------分割線------------------- *//* 邏輯組合偽類(lèi)有:not()、:is()和:where()需要注意的是,只有邏輯組合偽類(lèi)的優(yōu)先級(jí)是0,其他偽類(lèi)的優(yōu)先級(jí)并不是這樣的 */ :not() {color: #fff; }1級(jí):標(biāo)簽選擇器
/* 標(biāo)簽選擇器類(lèi)似于body,p,span,div等等這些標(biāo)簽元素 */ body {color: #333; }2級(jí):類(lèi)選擇器、屬性選擇器和偽類(lèi)
/* 類(lèi)選擇器指class */ .container {color: #666; }/* ------------------分割線------------------- *//* 屬性選擇器指指針對(duì)某個(gè)標(biāo)簽里面的屬性進(jìn)行特定標(biāo)識(shí)比如以下,表示只對(duì)有 href 屬性的錨(a 元素)應(yīng)用樣式 */ a[href] {color:#666; }/* ------------------分割線------------------- *//* 偽類(lèi)指:hover等 */ a:hover {color: #666; }3級(jí):ID選擇器
#container {color: #999; }4級(jí):style屬性?xún)?nèi)聯(lián)
<span style="color: #ccc;">優(yōu)先級(jí) </span>5級(jí):! important
/* !important是頂級(jí)優(yōu)先級(jí),可以重置 js 設(shè)置的樣式,唯一推薦使用的場(chǎng)景就是使 js 設(shè)置無(wú)效(切勿濫用)*/ #container {color: #999 !important; }2、優(yōu)先級(jí)計(jì)算
上面我們了解到了關(guān)于 css 選擇器的各種玩法,那下面我們就來(lái)看一下它是怎么玩的。
(1)選擇器優(yōu)先級(jí)計(jì)算
我們用一個(gè)表格來(lái)羅列處常見(jiàn)的一些計(jì)算。當(dāng)然,大家也可以拿起小本本邊看邊進(jìn)行計(jì)算。具體如下表:
| *{ } | 0 | 1個(gè)0級(jí)通配選擇器,優(yōu)先級(jí)數(shù)值計(jì)算結(jié)果為0 |
| p { } | 1 | 1個(gè)1級(jí)通配選擇器,計(jì)算結(jié)果為1 |
| ul > li { } | 2 | 2個(gè)1級(jí)標(biāo)簽選擇器,1個(gè)0級(jí)選擇符,計(jì)算結(jié)果為1+0+1 |
| li > ol + ol { } | 3 | 3個(gè)1級(jí)標(biāo)簽選擇器,2個(gè)0級(jí)選擇符,計(jì)算結(jié)果為1+0+1+0+1 |
| .foo { } | 10 | 1個(gè)2級(jí)類(lèi)名選擇器,計(jì)算結(jié)果為10 |
| a:not([rel=nofollow]) { } | 11 | 1個(gè)標(biāo)簽選擇器,1個(gè)0級(jí)否定偽類(lèi),1個(gè)2級(jí)屬性選擇器,計(jì)算結(jié)果為1+0+10 |
| a:hover { } | 11 | 1個(gè)1級(jí)標(biāo)簽選擇器,1個(gè)2級(jí)偽類(lèi),計(jì)算結(jié)果為1+10 |
| ol li.foo { } | 12 | 2個(gè)1級(jí)標(biāo)簽選擇器,1個(gè)2級(jí)類(lèi)名選擇器,1個(gè)0級(jí)空格選擇符,計(jì)算結(jié)果為1+0+1+10 |
| li.foo.bar { } | 21 | 1個(gè)1級(jí)標(biāo)簽選擇器,2個(gè)2級(jí)類(lèi)名選擇器,計(jì)算結(jié)果為1+10+10 |
| #foo { } | 100 | 1個(gè)3級(jí)id選擇器,計(jì)算結(jié)果為100 |
| #foo .bar p { } | 111 | 1個(gè)3級(jí)id選擇器,1個(gè)2級(jí)類(lèi)名選擇器,1個(gè)1級(jí)標(biāo)簽選擇器,2個(gè)0級(jí)空格選擇器,計(jì)算結(jié)果為100+10+1+0+0 |
(2)“后來(lái)居上”原則
還有一種可能會(huì)出現(xiàn)的情況就是,遇到計(jì)算結(jié)果相同的,我們?cè)撊绾稳≈的?#xff1f;比如:
<html lang=“zh-CN”><body class="foo">顏色是</body> </html><style>body.foo:not([dir]) {color: red;}html[lang] > .foo {color: blue;} </style>我們來(lái)分析下以上這段代碼。首先,第一段 css 代碼中,出現(xiàn)1個(gè)標(biāo)簽選擇器 body ,1個(gè)類(lèi)名選擇器 .foo 和1個(gè)否定偽類(lèi) :not ,以及1個(gè)屬性選擇器 [dir] 。因此計(jì)算結(jié)果為 1+10+0+10 ,也就是 21 。
我們?cè)賮?lái)分析第二段代碼, html[lang] > .foo 中出現(xiàn)1個(gè)標(biāo)簽選擇器 html ,1個(gè)屬性選擇器 [lang] ,1個(gè)類(lèi)名選擇器 .foo ,這里 0級(jí)選擇器 忽略不計(jì)。因此,最終計(jì)算結(jié)果為 1+10+10=21 。
所以,大家可以看到,兩個(gè)最終的計(jì)算結(jié)果都是 21 。那我們到底用哪個(gè)樣式呢?
印證標(biāo)題所說(shuō)的,遵循**“后來(lái)居上”原則**, 最終這段代碼顯示為藍(lán)色。
(3)提升優(yōu)先級(jí)的小技巧
在實(shí)際開(kāi)發(fā)中,我們難免會(huì)遇到需要增加 css 選擇器優(yōu)先級(jí)的場(chǎng)景。殊不知很多小伙伴可能直接就把內(nèi)聯(lián)和 !important 直接懟上去了,這樣子造成的后果可能有點(diǎn)恐怖了。
所以,我們需要來(lái)了解幾種增加選擇器權(quán)重的做法。具體如下:
假設(shè)現(xiàn)在我要給下面這段代碼增加權(quán)重,例如:
.foo {color: #333; }很多時(shí)候我們的做法可能是增加嵌套或者是增加一個(gè)標(biāo)簽選擇器,例如:
/* 增加嵌套 */ .father .foo {}/* 增加標(biāo)簽選擇器 */ div.foo {}但是這種做法往往不是最好的,因?yàn)樗鼤?huì)增加了代碼的耦合度,降低代碼的可維護(hù)性。試想一下,一旦類(lèi)名變了,或者標(biāo)簽換了,那你的樣式豈不是就要往回去改了,這樣會(huì)不會(huì)就有點(diǎn)不太友好了。
所以,我們引出一下兩種方式,來(lái)解決這個(gè)問(wèn)題。具體如下:
第一種: 重復(fù)選擇器自身
.foo.foo {}第二種: 借助已存在的屬性選擇器
.foo[class] {}#foo[id] {}這樣看起來(lái),會(huì)不會(huì)就友好了許多呢。
🥳三、結(jié)束語(yǔ)
在上文中,我們講到關(guān)于 css 選擇器的一些基礎(chǔ)知識(shí),以及 css 選擇器的優(yōu)先級(jí)的各種計(jì)算方式,還有關(guān)于“后來(lái)居上”原則和一些提升優(yōu)先級(jí)的小tips。
講到這里,關(guān)于 css 選擇器優(yōu)先級(jí)的講解就結(jié)束啦!希望對(duì)大家有幫助~
🐣彩蛋 One More Thing
🏷?往期推薦&參考資料
position和z-index👉你可能對(duì)position和z-index有一些誤解
書(shū)籍👉張?chǎng)涡窭蠋煹摹禖SS選擇器世界》
🏷?番外篇
- 關(guān)注公眾號(hào)星期一研究室,第一時(shí)間關(guān)注優(yōu)質(zhì)文章,更多精選專(zhuān)欄待你解鎖~
- 如果這篇文章對(duì)你有用,記得留個(gè)腳印jio再走哦~
- 以上就是本文的全部?jī)?nèi)容!我們下期見(jiàn)!👋👋👋
總結(jié)
以上是生活随笔為你收集整理的谁动了我的选择器?深入理解CSS选择器优先级的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 划船机减肥效果如何
- 下一篇: 2024年度北京普惠健康保服务增至49项