過(guò)往 css 優(yōu)先級(jí)中存在的問(wèn)題
如果我們的頁(yè)面上存在非常多的樣式,譬如有我們開(kāi)發(fā)頁(yè)面的時(shí)候的自定義樣式,也有引入的組件庫(kù)樣式。這時(shí)候樣式將會(huì)非常混亂難以管理。
當(dāng)我們想覆蓋一些本身非我們書(shū)寫(xiě)的樣式時(shí)候,往往不得不通過(guò)使用優(yōu)先級(jí)權(quán)重更高的樣式名,去覆蓋那些樣式。
同時(shí),當(dāng)樣式優(yōu)先級(jí)感到難以控制時(shí),開(kāi)發(fā)者習(xí)慣濫用 !important 去解決,這又循環(huán)導(dǎo)致了后續(xù)更混亂的樣式結(jié)構(gòu)。
基于讓 CSS 得到更好的控制和管理的背景,CSS @layer 應(yīng)運(yùn)而生。
何為 CSS @layer?
CSS Cascade Layers,也叫做CSS級(jí)聯(lián)層,是Cascading and Inheritance Level5 規(guī)范中新增了一個(gè)新的 CSS 特性。
@layer聲明了一個(gè) 級(jí)聯(lián)層, 同一層內(nèi)的規(guī)則將級(jí)聯(lián)在一起, 這給予了開(kāi)發(fā)者對(duì)層疊機(jī)制的更多控制。語(yǔ)法也非常簡(jiǎn)單,看這樣一個(gè)例子:
@layer utilities {
/* 創(chuàng)建一個(gè)名為 utilities 的級(jí)聯(lián)層 */
}
這樣,我們就創(chuàng)建一個(gè)名為 utilities 的 @layer 級(jí)聯(lián)層。
@layer語(yǔ)法
@layer規(guī)則可以通過(guò)三種方式其一來(lái)創(chuàng)建級(jí)聯(lián)層。第一種方法如上方代碼所示,它創(chuàng)建了一個(gè)塊級(jí)的@規(guī)則,其中包含作用于該層內(nèi)部的CSS規(guī)則。
@layer utilities {
.padding-sm {
padding: .5rem;
}
.padding-lg {
padding: .8rem;
}
}
一個(gè)級(jí)聯(lián)層同樣可以通過(guò) @import 來(lái)創(chuàng)建,規(guī)則存在于被引入的樣式表內(nèi):
@import(utilities.css) layer(utilities);
你也可以創(chuàng)建帶命名的級(jí)聯(lián)層,但不指定任何樣式。例如,單一的命名層:
@layer utilities
或者,多個(gè)命名層也可以被同時(shí)定義。例如:
@layer theme, layout, utilities
這一做法很有用,因?yàn)閷幼畛醣恢付ǖ捻樞驔Q定了它是否有父級(jí)層。對(duì)于聲明而言,如果同一聲明在多個(gè)級(jí)聯(lián)層中被指定,最后一層中的將優(yōu)先于其他層。
因此,在上面的例子中,如果 theme 層和 utilities 層中存在沖突的規(guī)則,那么 utilities 層中的將優(yōu)先被應(yīng)用。
即使 utilities 層中規(guī)則的 優(yōu)先級(jí)低于 theme 層中的,該規(guī)則仍會(huì)被應(yīng)用。一旦級(jí)聯(lián)層順序建立之后,優(yōu)先級(jí)和出現(xiàn)順序都會(huì)被忽略。
這將使創(chuàng)建CSS選擇器變得更加簡(jiǎn)單,因?yàn)槟悴恍枰_保每一個(gè)選擇器都有足夠高的優(yōu)先級(jí)來(lái)覆蓋其他沖突的規(guī)則,你只需要確保它們出現(xiàn)在一個(gè)順序更靠后的級(jí)聯(lián)層中。
注:在已經(jīng)聲明級(jí)聯(lián)層的名字后,它們的順序隨即被確立,你可以重復(fù)聲明某級(jí)聯(lián)層的名字來(lái)向其添加CSS規(guī)則。這些樣式將被附加到該層的末尾,且級(jí)聯(lián)層之間的順序不會(huì)改變。
其他不屬于任何一級(jí)聯(lián)層的樣式將被集中到同一匿名層,并置于所有層的前部,這意味著任何級(jí)聯(lián)層內(nèi)定義的規(guī)則都將覆蓋外部聲明的規(guī)則。
嵌套層
級(jí)聯(lián)層允許嵌套,例如:
@layer framework {
@layer layout {
}
}
向 layout 層內(nèi)部的 framework 層附加規(guī)則,只需用 . 連接這兩層。
@layer framework.layout {
p {
margin-block: 1rem;
}
}
匿名層
如果創(chuàng)建了一個(gè)級(jí)聯(lián)層但并未指定名字,例如:
@layer {
p {
margin-block: 1rem;
}
}
那么則稱(chēng)為創(chuàng)建了一個(gè)匿名層。除創(chuàng)建后無(wú)法向其添加規(guī)則外,該層和其他命名層功能一致。
標(biāo)準(zhǔn)語(yǔ)法
@layer [ <layer-name># | <layer-name>? {
<stylesheet>
} ]
@layer如何使用
創(chuàng)建級(jí)聯(lián)層
級(jí)聯(lián)層可以通過(guò)多種方式聲明:
1、使用@layer 塊規(guī)則,并立即為其分配樣式:
@layer reset {
* { /* Poor Man's Reset */
margin: 0;
padding: 0;
}
}
2、使用規(guī)則@layer 語(yǔ)句,沒(méi)有指定任何樣式:
@layer reset;
3、將@import 與layer關(guān)鍵字或layer()函數(shù)一起使用
@import(reset.css) layer(reset);
以上每一個(gè)都創(chuàng)建了一個(gè)名為 的級(jí)聯(lián)層reset。
管理級(jí)聯(lián)層
級(jí)聯(lián)層會(huì)按它們聲明的順序排序。
在下面的例子中,我們建立四個(gè)級(jí)聯(lián)層:reset,base,theme,和utilities。
@layer reset { /* 創(chuàng)建級(jí)聯(lián)層 “reset” */
* {
margin: 0;
padding: 0;
}
}
@layer base { /* 創(chuàng)建級(jí)聯(lián)層 “base” */
…
}
@layer theme { /* 創(chuàng)建級(jí)聯(lián)層 “theme” */
…
}
@layer utilities { /* 創(chuàng)建級(jí)聯(lián)層 “utilities” */
…
}
按照它們的聲明順序,層順序變?yōu)椋?/p>
reset
base
theme
utilities
重復(fù)使用級(jí)聯(lián)層名稱(chēng)時(shí),樣式將附加到現(xiàn)有級(jí)聯(lián)層。級(jí)聯(lián)層的順序保持不變,因?yàn)橹挥械谝淮蔚某霈F(xiàn)已經(jīng)確定順序:
@layer reset { /* 創(chuàng)建第一個(gè)級(jí)聯(lián)層 “reset” */
…
}
@layer base { /* 創(chuàng)建第二個(gè)級(jí)聯(lián)層 “base” */
…
}
@layer theme { /* 創(chuàng)建第三個(gè)級(jí)聯(lián)層 “theme” */
…
}
@layer utilities { /* 創(chuàng)建第四個(gè)級(jí)聯(lián)層 “utilities” */
…
}
@layer base { /* 會(huì)將樣式添加至級(jí)聯(lián)層“base” */
…
}
重新使用級(jí)聯(lián)層名稱(chēng)時(shí)層順序保持不變的使@layer 語(yǔ)法變得更加方便和嚴(yán)謹(jǐn)。使用它,可以預(yù)先建立圖層順序,然后將所有 CSS 附加到它:
@layer reset; /* 創(chuàng)建第一個(gè)級(jí)聯(lián)層 “reset” */
@layer base; /* 創(chuàng)建第二個(gè)級(jí)聯(lián)層 “base” */
@layer theme; /* 創(chuàng)建第三個(gè)級(jí)聯(lián)層“theme” */
@layer utilities; /* 創(chuàng)建第四個(gè)級(jí)聯(lián)層 “utilities” */
@layer reset { /* 添加樣式至級(jí)聯(lián)層 “reset” */
…
}
@layer theme { /* 添加樣式至級(jí)聯(lián)層 “theme” */
…
}
@layer base { /* 添加樣式至級(jí)聯(lián)層 “base” */
…
}
@layer theme { /* 添加樣式至級(jí)聯(lián)層 “theme” */
…
}
當(dāng)然你可以用更短的語(yǔ)法來(lái)聲明級(jí)聯(lián)層,
@layer reset, base, theme, utilities;
從上面可以看出,多個(gè)級(jí)聯(lián)層被聲明時(shí),最后一個(gè)級(jí)聯(lián)層的聲明會(huì)獲勝。像這樣,
@import(reset.css) layer(reset); /* 第一個(gè)級(jí)聯(lián)層 */
@layer base { /* 第二個(gè)級(jí)聯(lián)層 */
form input {
font-size: inherit;
}
}
@layer theme { /*第三個(gè)級(jí)聯(lián)層 */
input {
font-size: 2rem;
}
}
按以往CSS級(jí)聯(lián)來(lái)進(jìn)行分析的話,form input(多層級(jí))的優(yōu)先級(jí)會(huì)大于input,但是由于級(jí)聯(lián)層所起的作用,@layer theme的input會(huì)取勝。
級(jí)聯(lián)層嵌套
級(jí)聯(lián)層支持嵌套使用,如下:
@layer base { /* 第一個(gè)級(jí)聯(lián)層*/
p { max-width: 70ch; }
}
@layer framework { /* 第二個(gè)級(jí)聯(lián)層 */
@layer base { /* 第二級(jí)聯(lián)層的嵌套子級(jí)聯(lián)層1 */
p { margin-block: 0.75em; }
}
@layer theme { /* 第二級(jí)聯(lián)層的嵌套子級(jí)聯(lián)層2 */
p { color: #222; }
}
}
在這個(gè)例子中有兩個(gè)級(jí)聯(lián)外層:
base
framework
該framework層本身也包含兩層:
base
theme
如果要將樣式附加到嵌套級(jí)聯(lián)層,需要使用以下全名來(lái)引用它,
@layer framework {
@layer default {
p { margin-block: 0.75em; }
}
@layer theme {
p { color: #222; }
}
}
@layer framework.theme {
/* 這些樣式會(huì)被添加到@layer framework層里面的theme層 */
blockquote { color: rebeccapurple; }
}
@media與@layer
@media (min-width: 30em) {
@layer layout {
.title { font-size: x-large; }
}
}
@media (prefers-color-scheme: dark) {
@layer theme {
.title { color: white; }
}
}
如果第一個(gè)@media (min-width: 30em)匹配(基于視口尺寸),則layout級(jí)聯(lián)層層將在圖層順序中排在第一位。如果只有@media (prefers-color-scheme: dark)匹配,theme則將是第一層。
如果兩者匹配,則圖層順序?qū)閘ayout, theme。如果沒(méi)有匹配,則不定義層。