用 CSS 最困難的部分之一是處理特異性。如果您嘗試從像 Bootstrap 這樣的框架覆蓋樣式,這一點尤其明顯,但是隨著 CSS 層的引入,這一切都發生了變化。這個新功能允許您創建自己的自定義 CSS 層,這是有史以來第一次確定所有 CSS 代碼的特異性層次結構。在本文中,我將剖析這對您意味著什么,它是如何工作的,以及您今天如何開始使用它。
創建自己的自定義圖層的能力對于 CSS 來說是新功能,但圖層從一開始就在 CSS 中存在。CSS 中有 3 個不同的層來管理所有樣式的工作方式。
瀏覽器樣式是應用于瀏覽器的默認樣式。這就是為什么 Chrome 和 Safari 中的按鈕看起來不同的原因。在瀏覽器層中找到的樣式在瀏覽器之間是不同的,并且給每個瀏覽器一個獨特的外觀。
下一層是用戶樣式,這并不是您真正需要擔心的事情。這些通常是用戶可以編寫并注入瀏覽器的自定義樣式,但瀏覽器不再真正支持這些樣式。用戶可能會更改一些瀏覽器設置,這些設置會向該圖層添加樣式,但在大多數情況下,可以完全忽略該圖層。
最后,我們來到作者層。這是您最熟悉的層,因為您編寫的每一段 CSS 代碼都屬于這一層
層疊的規則是按照“樣式表來源”、“選擇器優先級”、“源碼順序”來考慮的,下圖展示了一個判定流程:
但是頁面一樣復雜,組件一多,樣式管理起來還是很費勁,很多時候還是得用自己不想用的一些「優先級」權重高的選擇器去覆寫樣式,比如ID或者 !important,所以CSS新出一個 @layer 特性,能讓樣式得到更好的管理和控制。
大家用過ps的話,很好理解 @layer ,它就像ps里的圖層一樣,可以對ps圖層進行排序,上面的圖層有更高的優先級,@layer 的一個重要作用,就是可以提前定義好“級聯層”的優先級:
@layer one {
#button.super-specific-selector {
color: red;
}
}
@layer two {
button {
color: green;
}
}
正如你在上面看到的,我們只是使用@layer關鍵字來創建一個自定義層,給它任何我們想要的名稱 。圖層two的樣式會覆蓋圖層one的樣式。one無論其特殊性如何。
如您所見,我們在作者樣式中創建了兩個新層,我們可以使用它們來組織我們的代碼并使使用特定性更容易。
如何將代碼添加到現有層。
@layer one {
#button.super-specific-selector {
color: red;
}
}
@layer two {
button {
color: green;
}
}
@layer one {
.another-style {
color: blue;
}
}
在這個例子中你可以看到我已經定義one了兩次圖層。這完全沒問題,實際上是在創建圖層后向圖層添加更多樣式的方式。這樣做不會影響層的順序,因為層的順序是由創建層的第一段代碼決定的。這意味著我們one在 CSS 文件頂部的第一個圖層實例將創建圖層,因此本示例中的圖層順序與上一個示例中的相同。唯一的區別是我們能夠在圖層one創建后通過@layer再次使用關鍵字來添加額外的樣式。等同如下
@layer one {
#button.super-specific-selector {
color: red;
}
.another-style {
color: blue;
}
}
@layer two {
button {
color: green;
}
}
這種在創建圖層后向圖層添加樣式的功能在定義圖層順序時非常有用。想象一下,您有以下幾層
@layer base,application;
@layer application {
em {
color: red;
}
}
@layer base {
.item em {
color: green;
}
}
通過@layer base,application;按從左到右的順序定義所有層,其中列出的base是最不具體的,最后指定的層application是最具體的。也是最先生效的。然后,您可以稍后使用正常@layer語法將代碼添加到每個層,而不必擔心定義層的順序,因為它們都在這一行中定義。需要注意的是,這行代碼必須在定義任何層之前出現,所以我通常將它作為我的 CSS 文件中的第一行。
很多時候,當你使用一個框架時,你可能會像這樣將它導入到你的 CSS 中。
@import url("your.css");
如果要將所有這些導入的代碼添加到特定層,只需添加layer(layer-name)到導入語句的末尾即可。
@import url("your.css") layer(layerName);
這會將所有樣式添加your.css到layerName圖層。但是,使用導入的一件事是它們的性能不是很好,因為首先您需要下載包含該@import語句的樣式表,然后瀏覽器才能下載導入的文件。解決此問題的一種方法是在 HTML 中使用style標簽。
<!-- link tag to stylesheet that define your layers -->
<link rel="stylesheet" href="styles.css">
<style>
@import url("your.css") layer(layerName);
</style>
通過像這樣編寫代碼,您可以避免所有性能問題,@import但仍然可以獲得直接導入圖層的所有好處
匿名層指的是不聲明layer名地級聯層,它在級聯層中的優先級,取決于layer聲明次序:
@layer A {
body {
background-color: green;
}
}
@layer {
body {
background-color: red;
}
}
@layer B {
body {
background-color: bisque;
}
}
優先級從高到低為:B > 匿名 > A,所以最后生效的body背景色為bisque。這并不是我覺得太有用的東西,但如果你真的需要將少量的 CSS 代碼分成一個層,這可能會很有用。
我認為不太有用的另一個功能是能夠將圖層相互嵌套
@layer outer {
@layer inner {
.button {
color: red;
}
}
}
@layer outer.inner {
.another {
color: green;
}
}
通過使用上面的.語法或嵌套語法,您可以在其他層內創建層。這是您可能不會經常使用的東西,因為大多數應用程序只有幾層,但如果您有一個非常復雜或大型樣式系統,這可能會很有用。
這涵蓋了創建圖層的基礎知識,但是您需要了解一些關于圖層的概念才能充分利用圖層。
到目前為止,我們只處理了所有樣式都在圖層中的 CSS。當您的樣式沒有圖層時,事情會變得有點復雜。
body {
background-color: blue;
}
@layer A {
body {
background-color: red;
color: black;
}
}
@layer B {
body {
color: blue;
background-color: green;
}
}
在這個例子中,我們有兩個個A和B圖層,然后是一個沒有圖層的樣式。當您的代碼不在任何層中時,它總是被認為比分層代碼更具體。這意味著我們的有一個藍色的背景。為了使這一點更容易理解,我喜歡將不在任何層中的代碼視為在所有其他層之后定義的自己的層中。
這有助于我可視化我的代碼,因此我可以理解為什么非分層代碼總是覆蓋層內的代碼。
該!important關鍵字使使用特異性變得困難,并且對于圖層來說也沒有什么不同。該!important關鍵字的工作方式與普通圖層完全相反。如果您使用!important關鍵字定義樣式,它將覆蓋該層之后定義的層中的任何樣式。
@layer one {
button {
color: red !important;
}
}
@layer two {
button {
color: green;
}
}
在上面的例子中,按鈕文本將是紅色的,因為我們之前!important定義了顏色。但是,如果我們嘗試添加!important到 layertwo以覆蓋!important來自圖層one,它實際上不會更改按鈕顏色。
@layer one {
button {
color: red !important;
}
}
@layer two {
button {
color: green !important;
}
}
這樣做的原因是因為它!important的工作方式與普通圖層相反。由于 layerone是在 layer 之前定義的,所以 layer中的two所有!important樣式one都會覆蓋 layer 中的任何樣式,包括!important樣式two。這意味著我們的按鈕仍然是紅色的。
如果我再加一個沒有圖層!important的普通樣式,按鈕又是什么顏色的呢?
@layer one {
button {
color: red !important;
}
}
@layer two {
button {
color: green !important;
}
}
button{
color: blue !important;
}
根據非分層樣式更先生效,那自然按鈕會是藍色的。
對于每一個很酷的 CSS 功能,你總是需要考慮瀏覽器的支持,但幸運的是,對我們來說,圖層得到了很好的支持,并且很快就會得到完美的支持。目前,layer有84.31% 的支持率,但這主要是因為這個功能最近才在最新版本的瀏覽器中推出。大多數現代瀏覽器在撰寫本文時不到一個月前就推出了此功能,這意味著我們目前只是在等待用戶將他們的瀏覽器更新到最新版本以支持此功能。
總之,@layer 還是蠻好用的,希望能盡快在業務代碼里面用到吧。
介:本文介紹使用Python,爬取國家統計局網站區劃和城鄉劃分代碼數據,并保存為不同的格式。該功能可為電商等行業規范客戶郵寄地址的填寫提供幫助。
行政區劃數據取自國家統計局網站(http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/),數據按行政級別由大到下通過鏈接和純html文本嵌套呈現。如河北省:
獲取頂級區域(省/直轄市/自治區,不含港澳臺)的地址是 http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2021/index.html。其中的“2021”代表數據時間版本。
區劃代碼格式定義參見“民政部行政區劃規則(https://www.mca.gov.cn/article/sj/xzqh/1980/)”。
通過Python分析網頁,從頂級區域自動識別各級子區域代碼和名稱,并保存為不同的數據格式,以供其他業務進一步使用。本Python程序可將爬取后的數據另存為
以河北省為例:文件名中的13是河北省區劃代碼;文件中ID是自定義的數據主鍵,2021是數據版本號。
html表格文件,文件名 address_model_13.html
Excel格式文件:文件名 address_model_13.xlsx
sql格式文件:文件名 address_model_13.sql
json格式文件:文件名 address_model_13.json。json格式文件是按行政區域的級聯形式,不帶ID和版本號字段。
Python需要本版3.5以上,且要安裝requests,pandas,BeautifulSoup庫
程序可在命令行直接運行:
python AddressUtil.py
參數在程序中設置,分別是
province:頂級區域代碼,province = 0時獲取頂級區域數據,可用于測試,減少獲取數據等待的時間
out_format:輸出格式
參數取值見源程序
程序運行時會打印獲取的區域進度和異常
出現“request timeout”時說明由于網絡問題未獲取網頁需要重試。本程序設置了三次重試,如三次重試仍未獲取,則程序退出,請檢查你的網絡連接和統計局網站是否有問題。
區劃代碼數據的使用,引用統計局網站原文——“統計用區劃代碼和城鄉劃分代碼用于統計工作,需要在其他工作中使用時,請務必結合有關實際情況。”
本文涉及的Python程序和數據樣例可從百度網盤下載
https://pan.baidu.com/s/1Jhd_4NPn12WtteOW3IP3AA?pwd=1234 提取碼: 1234
特別聲明:本人保留源程序版權,源程序可供任何人自由使用(包括商業行為),本人不對使用本程序的后果承擔任何責任。使用時請標注或保留原作者名:雙魚菜青蟲(賬號)。
近在Weekly郵件推送中查閱到這樣的一條信息:
Chromium 團隊宣布他們將隨 Chromium 99(預計在明年 3 月發布)一起發布CSS Cascade Layers
會發現這條信息里面出現了一個CSS的新名詞CSS Cascade Layers,出于好奇以及對新知識的渴望(說得我自己都信了,哈哈),于是查閱起CSS Cascade Layers的相關資料,試圖搞懂它。
前置知識
at-rule規則, CSS Conditional Rules Module Level 3新增的規則,是一條語句,它為CSS提供了執行或如何執行的指令,常見的at-rule規則有:
@import,允許用戶從其他樣式表導入樣式規則
@font-face,允許我們引用自定義的字體
@keyframes,聲明一個動畫
@media,是條件CSS中的一種,其條件是一個媒體查詢
@supports,測試用戶代理是否支持CSS屬性/值對
@viewport,用來控制移動設備上的viewport設置
級聯(層疊)與繼承經過多年的發展迭代,目前已有多個版本(CSS2.2、Level3、Level4 和 Level5)
何為級聯(層疊)?
層疊本質就是定義了如何合并來自多個源的屬性值的算法,簡單來說,CSS規則的順序很重要。當兩條同級別的規則應用到一個元素的時候,寫在后面的就是實際使用的規則。
h1 {
color: red;
}
h1 {
color: blue;
}
兩條規則優先級相同,所以順序在最后的生效,h1是color:blue'勝出',顯示藍色。
只有CSS聲明,就是屬性名值對,會參與層疊計算。這表示包含CSS聲明以外實體的@規則不參與層疊計算,如包含描述符的@font-face,@規則(at-rule規則)是做為一個整體參與層疊計算。
css屬性一般來自于哪幾個源?
1、用戶代理樣式表:瀏覽器的基本的樣式表,用于給所有網頁設置默認樣式。
2、用戶樣式表:網頁的作者可以定義文檔的樣式。大多數情況下此類型樣式表會定義網站的主題。
3、瀏覽器的用戶使用自定義樣式表定制使用體驗。
層疊(級聯)算法如何過濾來自不同源的css規則?
相互沖突的聲明按以下順序適用,后一種聲明將覆蓋前一種聲明:
1、用戶代理樣式表中的聲明(瀏覽器的默認樣式)。
2、用戶樣式表中的常規聲明(用戶設置的自定義樣式,就如同我們的reset.css)。
3、作者樣式表中的常規聲明(開發人員設置的樣式)。
4、作者樣式表中的!important聲明
5、用戶樣式表中的!important 聲明
過濾來自不同源的css規則后,確定同源優先級高低,決定誰“優勝”
!important > 內聯style > #id > .class > 標簽
了解級聯算法有助于幫助我們理解瀏覽器是如何解決樣式規則沖突,也就是瀏覽器決定哪個樣式規則運用到元素上,更多相關css級聯的了解:
何為繼承?
當元素的一個繼承屬性沒有指定值時,則取父元素的同屬性的計算值 。只有文檔根元素取該屬性定義的默認值,類似的屬性有color、font-size等 。
CSS是由Cascading Style Sheets三個詞的首字母縮寫,很多人將其稱為層疊樣式表或者級聯樣式表.
CSS Cascade Layers,也叫做CSS級聯層,是Cascading and Inheritance Level5 規范中新增了一個新的 CSS 特性,對應的CSS屬性寫法@layer,即一個新的 @ 規則,也就是大家所說的at-rule 規則。
為啥會出現@layer?
通過上面我們對級聯介紹,我們已經看到了順序對于層疊的重要性,同權重的css屬性后者會“優勝”前者,權重不同會根據CSS聲明來源和優先級算法來判斷誰“優勝”。!important的CSS規則自動將它跳到層疊算法的前面,能夠覆蓋普通規則的層疊。
也就是說我們一般會使用選擇器權重和順序作為控制級聯的方法,但是這樣卻會時常碰到:
使用較高權重的選擇器來防止你的代碼被后面的代碼(或別人的代碼)覆蓋。但這也會引起另一個不良的現象,可能會在代碼中新增很多帶有 !important 的樣式規則,這本身就會引起更多的問題,比如 !important 在 CSS 樣式表中隨處可見,需要覆蓋的時候難以被覆蓋 。
使用較低權重的選擇器又很容易被后面的代碼(或別人的代碼)覆蓋。比如你在引入第三方代碼庫或組件時,自己的代碼可能被覆蓋。
這兩個現象也是編寫CSS代碼,特別是在一個大型項目或多人協作的項目中常出現。也給很多CSS開發者帶來很多困擾。
雖然社區有很多第三方方案,如CSS-in-JS、CSS Modules 和 CSS Scoped等來協助解決級聯所帶來的問題,但由于源碼順序(打包產物)仍然起著決定性的作用,順序帶來的覆蓋和沖突依舊未真正的解決,而且選擇器權重仍然比層的順序(源碼順序)更重要。
這樣的背景促進了@layer的出現,要真正的解決級聯帶來的這些問題。
@layer的出現,也要求我們對以往css級聯有個新的了解,
可以看出CSS的級聯層一般位于“Style 屬性”(Style Attribute)和 CSS 選擇器權重(Specificity)之間。
使用CSS級聯層,可以通過@layer at-rule將 CSS 分成多個層。
與 CSS屬性來源 在用戶樣式表和作者樣式表風格之間提供權衡的方式相同,Cascade Layers 提供了一種結構化的方式來組織和權衡單個 來源 內的關注點
如何使用
級聯層可以通過多種方式聲明:
1、使用@layer 塊規則,并立即為其分配樣式:
@layer reset {
* { /* Poor Man's Reset */
margin: 0;
padding: 0;
}
}
2、使用規則@layer 語句,沒有指定任何樣式:
@layer reset;
3、將@import 與layer關鍵字或layer()函數一起使用
@import(reset.css) layer(reset);
以上每一個都創建了一個名為 的級聯層reset。
級聯層會按它們聲明的順序排序。
在下面的例子中,我們建立四個級聯層:reset,base,theme,和utilities。
@layer reset { /* 創建級聯層 “reset” */
* {
margin: 0;
padding: 0;
}
}
@layer base { /* 創建級聯層 “base” */
…
}
@layer theme { /* 創建級聯層 “theme” */
…
}
@layer utilities { /* 創建級聯層 “utilities” */
…
}
按照它們的聲明順序,層順序變為:
reset
base
theme
utilities
重復使用級聯層名稱時,樣式將附加到現有級聯層。級聯層的順序保持不變,因為只有第一次的出現已經確定順序:
@layer reset { /* 創建第一個級聯層 “reset” */
…
}
@layer base { /* 創建第二個級聯層 “base” */
…
}
@layer theme { /* 創建第三個級聯層 “theme” */
…
}
@layer utilities { /* 創建第四個級聯層 “utilities” */
…
}
@layer base { /* 會將樣式添加至級聯層“base” */
…
}
重新使用級聯層名稱時層順序保持不變的使@layer 語法變得更加方便和嚴謹。使用它,可以預先建立圖層順序,然后將所有 CSS 附加到它:
@layer reset; /* 創建第一個級聯層 “reset” */
@layer base; /* 創建第二個級聯層 “base” */
@layer theme; /* 創建第三個級聯層“theme” */
@layer utilities; /* 創建第四個級聯層 “utilities” */
@layer reset { /* 添加樣式至級聯層 “reset” */
…
}
@layer theme { /* 添加樣式至級聯層 “theme” */
…
}
@layer base { /* 添加樣式至級聯層 “base” */
…
}
@layer theme { /* 添加樣式至級聯層 “theme” */
…
}
當然你可以用更短的語法來聲明級聯層,
@layer reset, base, theme, utilities;
從上面可以看出,多個級聯層被聲明時,最后一個級聯層的聲明會獲勝。像這樣,
@import(reset.css) layer(reset); /* 第一個級聯層 */
@layer base { /* 第二個級聯層 */
form input {
font-size: inherit;
}
}
@layer theme { /*第三個級聯層 */
input {
font-size: 2rem;
}
}
按以往CSS級聯來進行分析的話,form input(多層級)的優先級會大于input,但是由于級聯層所起的作用,@layer theme的input會取勝。
級聯層支持嵌套使用,如下:
@layer base { /* 第一個級聯層*/
p { max-width: 70ch; }
}
@layer framework { /* 第二個級聯層 */
@layer base { /* 第二級聯層的嵌套子級聯層1 */
p { margin-block: 0.75em; }
}
@layer theme { /* 第二級聯層的嵌套子級聯層2 */
p { color: #222; }
}
}
在這個例子中有兩個級聯外層:
base
framework
該framework層本身也包含兩層:
base
theme
就像一棵樹,像這樣,
如果要將樣式附加到嵌套級聯層,需要使用以下全名來引用它,
@layer framework {
@layer default {
p { margin-block: 0.75em; }
}
@layer theme {
p { color: #222; }
}
}
@layer framework.theme {
/* 這些樣式會被添加到@layer framework層里面的theme層 */
blockquote { color: rebeccapurple; }
}
@media (min-width: 30em) {
@layer layout {
.title { font-size: x-large; }
}
}
@media (prefers-color-scheme: dark) {
@layer theme {
.title { color: white; }
}
}
如果第一個@media (min-width: 30em)匹配(基于視口尺寸),則layout級聯層層將在圖層順序中排在第一位。如果只有@media (prefers-color-scheme: dark)匹配,theme則將是第一層。
如果兩者匹配,則圖層順序將為layout, theme。如果沒有匹配,則不定義層。
隨著 Cascade Layers 的出現,我們的開發人員將擁有更多的工具來控制 Cascade。Cascade Layers 的真正力量來自它在 Cascade 中的獨特位置:Style 屬性(Style Attribute)和 CSS 選擇器權重(Specificity)之間。因此,我們不需要擔心其他層中使用的 CSS 的選擇器特異性,也不需要擔心我們將 CSS 加載到這些層中的順序.
了解到這里,是不是覺得@layer相當地cool,迫不及待地想去使用了,我們看一下caniuse @layer的兼容情況,
很遺憾,支持程度慘不忍睹,想真正使用可能還要再等等,對于明年三月份 Chromium 99,發布我們拭目以待。
當然現在如果想嘗鮮,對于社區也有給出一些辦法,
大家也可以試一試,感謝閱讀!
*請認真填寫需求信息,我們會在24小時內與您取得聯系。