CSS 選擇發展到今日,能夠說是一個龐大的體系了:前端
2021 CSS 的新特性和以前兩年的相比有類似也有不一樣,本文就帶你們看看今年的 CSS 到底說了什麼。javascript
簡介php
若是您有關注過這兩年的 CSS 發展狀態報告(2019年和2020年)的話,不難發現,在報告中有專門關於 CSS 新特性一項的介紹。
css
CSS僞類選擇器html
圖片by @linxz 的博客java
如今描述 CSS 選擇器的規範主要有 CSS (指的是 CSS 2.1),後面分爲選擇器 Level 3 和 Level 4。僞類選擇器在這三部分規範中都有出現過,他們是一個遞進的過程,特別是在 Level 3 和 Level 4,在原有的基礎上新增了很多優秀的選擇器。今天要提到的幾個現代僞類選擇器就是出於 Levele 4:ios
▐ :is() 和 :where()
Demo 地址:https://codepen.io/airen/full/ExWxbKe
:is(.header, .main) .p { color: purple}:where(.header, .main) .p { color: red;}
.header .p,.main .p { color: purple;}.header .p,.main .p { color: red;}
.header .p,.main .p { // ...}
:is(.header, .main) .p { // ...}
:where(.header, .main) .p { // ...}
.header .p,.main .p { // ....}
:is(.header, .main) .p { // ...}
:where(.header, .main) .p { // ...}
.p { // ...}
Level 0 h1 { 30px; : }Level 1 section h1, article h1, aside h1, nav h1 { 25px; : }Level 2 section section h1, section article h1, section aside h1, section nav h1,article section h1, article article h1, article aside h1, article nav h1,aside section h1, aside article h1, aside aside h1, aside nav h1,nav section h1, nav article h1, nav aside h1, nav nav h1, { 20px; : }
// Level 0h1 { font-size: 30px;}// Level 1:is(section, article, aside, nav) h1 { font-size: 25px;}// Level 2 :is(section, article, aside, nav):is(section, article, aside, nav) h1 { font-size: 20px;}
<!-- HTML --><main class="main"> <p class="p">What is the text color?</p></main>// CSS:where(.header, .main) .p { color: red;}.p { color: blue;}:is(.header, .main) .p { color: purple;}.header .p,.main .p { color: green;}
查看答案:https://codepen.io/airen/full/dyvyJmW
▐ :not() 和 :has()
或許你們平時在開發前端頁面的時候,碰到相似下圖這樣的需求:web
.card + .card { margin-top: 20px;}
// 或
.card { margin-bottom: 20px;}
.card.card--last { // 也可能會使用 .card:last-child margin-bottom: 0;}
.card:not(:last-child) { margin-bottom: 20px}
Demo URL: https://codepen.io/airen/full/MPNLEo
有人提出但願有一個
:parents()
這樣的選擇器!typescript
<section><!-- section 邊框顏色是 blue,margin-bottom是 30px --> <h1>H1 Level Title</h1></section>
<section><!-- section 邊框顏色是 #09f,margin-bottom是 30px --> <h1>H2 Level Title</h1></section>
<section><!-- section 邊框顏色是 red --> <p>Text Paragraphs</p></section> /* CSS */
// 將匹配含有h1子元素的 section元素section:has(h1) { border-color: blue;}// 將匹配含有h2子元素的 section元素section:has(h2) { border-color: #09f;}// 將匹配含有p子元素的 section元素section:has(p) { border-color: red;}// 將匹配除了含有p子元素的 section元素section:not(:has(p)) { margin-bottom: 30px;}
在支持:has()的瀏覽器中,你將看到下圖這樣的效果:canvas
示例中還演示了 :not() 和 :has() 組合在一塊兒使用的,但二者組合在一塊兒所達到的意思卻徹底不同。
其中 :not(:has(selector)) 匹配不含有 selector 元素的父元素,而 :has(:not(selector)) 匹配含有的不是 selector 子元素的元素。
二者主要區別在於,:has(:not(selector)) 寫法必需要含有一個子元素,而 :not(:has()) 能夠不含有元素也會被匹配。
有意思的是,Github 中有一個 Issue 在討論** **:has-child()** 選擇器**,或許哪一天,咱們在組件中就能夠這樣使用:
▐ :empty 和 :blank
在現代 Web 的開發的過程當中,老是沒法避免數據吐出爲空的狀況,此時每每會給咱們的 UI 帶來額外的麻煩。好比說,在同一類的 UI 元件中編寫了必定的樣式規則,但數據爲空,此時在頁面上可能會出現這樣的場景:
CSS 的 :empty 和 :blank兩個僞類選擇器能夠幫助咱們避免這種現象。這兩個選擇器都頗有用:
給空元素添加樣式
建立空的狀態
既然都是能夠爲空元素添加樣式,那何爲空元素,他們之間的差別又是什麼?先來回答第一個問題,何爲空元素?空元素是指元素沒有任何子元素或子節點,好比:
<!-- 空元素 --><div class="error"></div><div class="error"><!-- 註釋 --></div>
<!-- 非空元素 --><div class="error"> </div><!-- 中間有一個空格符 --><div class="error"></div><!-- 斷行 --><div class="error"> <!-- 註釋 --></div><!-- 註釋斷行排列 --><div class="error"><span></span></div>
:empty 和 :blank 相比,:empty 只能選中沒有子元素的元素。子元素只能夠是元素節點或文本(包括空格)。註釋或處理指令都不會產生影響。
Demo: https://codepen.io/airen/full/yLMLKyo
注意,在空元素上即便使用僞元素 ::before 或 ::after 建立內容,也能被:empty 識別。
:blank 要比 :empty 靈活地多,只要該元素中無任何子元素都能被識別。
不過 W3C 規範對該僞類選擇器的定義更趨向於做用到表單控件中,好比用戶沒有在 input 或 textarea 中輸入內容時,提交表單能被識別到。有點相似於表單驗證的功能。
早在 2018 年 Zell Liew 在推特上就針對 :empty 和 :blank 作過相關的討論,並發表一了篇有關於這方面的博文《:empty and :blank》:
到目前爲止,:empty 已獲得主流瀏覽器支持,能夠用於實際生產中,但 :blank 僞類選擇器仍是存在必定的爭議的。
▐ :focus-visible 和 :focus-within
-
:focus :當用戶使用鼠標點擊焦點元素或使用鍵盤的 Tab 鍵(或快捷鍵)觸發焦點元素焦點環的樣式 -
:focus-visible :只有使用鍵盤的 Tab 鍵(或快捷鍵)觸發焦點元素焦點環的樣式。若是僅使用 :focus-visible 設置焦點環樣式的話,那麼用戶使用鼠標點擊焦點元素時不會觸發焦點環樣式 -
:focus-within:表示一個元素得到焦點,或該元素的後代元素得到焦點。這也意味着,它或它的後代得到焦點,均可以觸發 :focus-within
button:focus { outline: 2px dotted #09f; outline-offset: 2px; }
button:focus-visible { outline: 2px solid #f36; outline-offset: 2px; }
button:focus-visible { outline: 2px solid #f36; outline-offset: 2px; }
button:focus { outline: 2px dotted #09f; outline-offset: 2px; }
button:focus:not(:focus-visible) { outline: 2px dotted #416dea; outline-offset: 2px; box-shadow: 0px 1px 1px #416dea;}
button:focus-visible { outline: 2px solid #416dea; outline-offset: 2px; box-shadow: 0px 1px 1px #416dea;}
Demo: https://codepen.io/airen/full/YzGdoLq
.box:focus-within,.container:focus-within { box-shadow: 0 0 5px 3px rgb(255 255 255 / 0.65);}
body:focus-within { background-color: #2a0f5bde;}
html:focus-within { border: 5px solid #09f;}複製代碼
Demo: https://codepen.io/airen/full/JjRxoLE
Demo: https://codepen.io/airen/full/KrPLmV
有了 :focus 、:focus-visible 和 :focus-within 會讓咱們更好的管理焦點元素在焦點狀態下焦點環的 UI 效果。
在 CSS 的世界中,除了這裏提到的僞類選擇器以外,還有不少其餘的僞類選擇器(或僞元素),好比 ::marker 、:in-range 、:out-of-range 。
若是你感興趣的話,能夠嘗試着使用 :in-range 、:out-of-range 給一些 input (好比 type 爲 number、range 的 input 元素,他們都有 min 和 max 屬性的設置) 在用戶輸入範圍值和非範圍值時,提供不一樣的 UI 效果。
CSS 顏色
CSS 顏色模塊自從 Level 4 開始,除了新增了一些新的函數值,好比 hwb()、lch()、lab() 、color-mix() 、 color-contrast() 和 color() 以外,對本來的 rgb() 、hsl() 以及 #rrggbb 等顏色值定義語法規則也作出調整。
好比,本來咱們熟悉的描述顏色值的方式:
#09f #90eafergb(123, 123, 123)rgba(123, 123, 123, .5)hsl(220, 50%, 50%)hsla(220, 50%, 50%, .5)
另外,十六進制描述顏色,也能夠在本來的語法規則中最後兩位添加新的位值來描述透度明。好比 #rrggbbaa 或 #rgba 。在Chrome 瀏覽器代碼審查器中,已經能夠看到這種語法規則的身影了:
也就是說,咱們如今能夠這樣來描述顏色值:
#hex-with-alpha { color: #0f08; color: #00ff0088;}
#functional-notation { color: hsl(0deg 0% 0%); color: hsl(2rad 50% 50% / 80%); color: rgb(0 0 0); color: rgb(255 255 255 / .25);}
#lab-and-lch { --ux-gray: lch(50% 0 0); --rad-pink: lch(50% 200 230); --rad-pink: lab(150% 160 0); --pale-purple: lab(75% 50 -50);}
另外,咱們如今描述顏色都是在sRBG 色值空間,而顏色色值空間是一個複雜的體系,除了 sRGB 以外還有其餘的色值空間,好比說 LCH:
正如上圖所示,LCH 顏色空間的顏色數量要比 sRGB 顏色空間的多,並且描述的顏色更爲細膩。
如上圖所示,能夠在color() 函數中指定顏色空間:
--rad-pink: color(display-p3 1 0 1); --rad-pink: color(lab 50% 150 -50); --rad-pink: color(srgb 100% 0% 50%);}
注意,使用了color() 函數指定顏色空間除了要考慮該函數支持度(瀏覽器的兼容性)還須要考慮硬件設備對顏色空間的支持度。
在 CSS 中能夠藉助媒體查詢 @media 來作相應的判斷,好比下面的示例,若是終端設備支持的話,就會採用指定顏色空間的色值:
dynamic-range: high) { ( .neon-pink { --neon-glow: color(display-p3 1 0 1); }
.neon-green { --neon-grow: color(display-p3 0 1 0); }}
更爲強大的是 CSS 顏色模塊 Level 5 版本,對顏色函數能力作了進一步的擴展。好比,能夠在 rgb()、hsl() 、hwb() 、lab() 和 lch() 函數基礎上添加 from 關鍵詞,實現基於一個顏色的基礎上,只對某個參數作調整:
rgb() = rgb([from <color>]? <percentage>{3} [ / <alpha-value> ]? ) | rgb([from <color>]? <number>{3} [ / <alpha-value> ]? ) hsl() = hsl([from <color>]? <hue> <percentage> <percentage> [ / <alpha-value> ]? ) hwb() = hwb([from <color>]? <hue> <percentage> <percentage> [ / <alpha-value> ]? ) lab() = lab([from <color>]? <percentage> <number> <number> [ / <alpha-value> ]? ) lch() = lch([from <color>]? <percentage> <number> <hue> [ / <alpha-value> ]? )複製代碼
來看一個 hsl() 的示例:
上圖展現的是,基於 --theme-primary (原色,即 hsl(274, 61%, 50%))顏色只對l 參數作調整,從 50% 調整到 30% ,從而得到一個新的顏色,即 hsl(274, 61%, 30%) 。使用這樣的方式,咱們就能夠很輕易的獲取基於某個顏色參數改變得來的顏色面板:
除此以外, 顏色模塊 Level 5 版本還新增了一些新的函數用來描述顏色,好比 color-mix() 、color-contrast() 、color-adjust() 等:
.color-mix { --pink: color-mix(red, white);
--brand: #0af; --text1: color-mix(var(--brand) 25%, black); --text2: color-mix(var(--brand) 40%, black);}
.color-contrast { color: color-contrast( var(--bg) vs black, white );}
--text-on-bg: color-contrast( var(--bg-blue-1) vs var(--text-subdued), var(--text-light), var(--text-lightest));
.color-adjust { --brand: #0af; --darker: color-adjust(var(--brand) lightness -50%); --lighter: color-adjust(var(--brand) lightness +50%);}
簡單介紹一下這幾個顏色函數。其中 color-mix() 函數接受兩個 <color> 值,並在給定的顏色空間中以指定的數量返回它們混合的結果。若是沒有特殊說明,不然在 lch() 顏色空間中進行混合。好比下圖所展現的就是 在lch() 顏色空間(默認)中將 red 和 yellow 混合,每一個 lch 通道的紅色值佔65%,黃色值佔 35%,即 color-mix(red yellow 65%) :
color-contrast() 函數頗有意思,它能夠幫助咱們提升Web可訪問性方面的能力。其主要做用是獲取一個顏色值,並將其與其餘顏色值的列表進行比較,從列表中選擇對比度最高的一個。
好比 color-contrast(white vs red, white, green) ,分別會拿 red 、white 和 green 與 white 對比,其中 green 與 white 對比度最高,最終會取 green 顏色:
color-adjust() 函數可用來在給定顏色空間中經過指定的變換函數對該顏色進行調整,除非另有規定,不然調整是在 lch() 色彩空間中進行的。好比 color-adjust(#0af lightness +50%) 是顏色 #0af 在 lch 顏色空間中高度增長 50% 。
也就是說,在不久的將來,這些顏色函數能夠很好的幫助咱們控制Web中的顏色值。由於這些顏色函數都已成爲主流瀏覽器的實驗性屬性,特別是 Safari 瀏覽器,對這方面的支持度要高於 Chrome 和 Firefox 瀏覽器。
CSS 背景
CSS 的 background 屬性是一個簡寫屬性,這個對於你們來講再熟悉不過了。不過在這裏着重想把 background-position 和 background-repeat 單獨拿出來和你們聊聊。你可能會問,這兩個屬性又不是什麼新屬性了,有什麼值得聊的呢?其實未必,這兩個屬性雖然老,但有幾個小細節對於不少開發者來講仍是會感到陌生的。我們先從 backgroundd-position 開始。
▐ background-position
background-position 主要是用來指定背景圖片在容器中的位置。你們較爲熟悉的是,背景圖片左上角(頂點)相對於容器左上角計算,以下圖所示:
不過,有的時候,但願背景圖片能相對於容器右側邊緣或底部邊緣計算,好比下圖:
要讓背景圖片距離容器右側邊緣和底部邊緣都是 50px 。針對這樣的場景,你或許首先會想到使用容器大小和背景圖片大小進行計算,得出距離頂部和左側邊緣的距離,而後將計算出來的值運用於 background-position 中。固然,熟悉 CSS 的同窗或許會想到使用 calc() 函數:
:root { --xPosition: 50px; --yPosition: 50px;}
.container { background-position: calc(100% - var(--xPosition) calc(100% - var(--yPosition)))}
使用 calc() 動態計算要比經過容器和背景圖片尺寸大小計算方便得多。
事實上呢?background-position 提供了另外一種特性,咱們能夠經過關鍵詞 top 、right 、bottom 和 left 來指定方向。好比咱們熟悉的用法 :
background-position: 50px 50px;
// 至關於background-position: top 50px left 50px;
那麼,咱們要實現上圖的效果,就可使用 right 和 bottom 關鍵詞,讓事情變得很是簡單:
:root { --xPosition: 50px; --yPosition: 50px;}
.container { background-position: right var(--xPosition) bottom var(--yPosition);}
最終效果以下:
Demo: codepen.io/airen/full/…
注,示例中左側是使用 calc() 計算的效果,右側使用的是關鍵詞實現的效果。
background-position 使用還有一個小細節須要注意,即 background-position 採用百分比值。由於使用百分比值的 background-position 計算會相對於其餘單位值複雜:
正如上圖所示,背景圖片原始尺寸是 100px x 100px ,容器的尺寸(使用該背景圖片的元素)是 410px x 210px ,若是使用 background-position: 75% 50% 時,它的計算以下:
// background-position的x軸座標x = (容器寬度 - 背景圖片寬度) x background-position的x座標的百分比值 = (410 - 100) x 75% = 232.5px
// background-position的y軸座標y = (容器高度 - 背景圖片高度) x background-position的y座標的百分比值 = (210 - 100) x 50% = 55px
就該示例而言,background-position: 75% 50% 就至關於 bacckground-position: 232.5px 55px。
注意,若是咱們把 background-size 和 background-position 取百分比值場景結合起來使用的時候,會讓事情變得更爲複雜,特別是background-size取值爲cover 或contain 更會讓你感到蛋疼。爲何會這樣呢?這已經超出來這篇文章所要探討的話題,若是你感興趣的話,能夠以此爲課題,深刻探討一下。
▐ background-repeat
在 background-repeat 屬性上除了可使用咱們熟悉的 no-repeat 和 repeat (或者 repeat-x 和 repeat-y) 以外還可使用 round 和 space 。
咱們都知道,使用 repeat 的時候,有可能會形成背景圖片在平鋪的時候被裁剪。若是但願背景圖片在平鋪時不被剪切,那麼可使用 round 來替代,它的最大特點就是背景圖片在平鋪的時候會根據容器的寬高對背景圖片作相應的尺寸調整。而 space 會留出相應的空間,即在保證背景圖片不被裁剪的狀況之下,對多出來的空間以空白的方式在背景圖片之間留出。
針對於這些值,我錄製了一個簡單的視頻,從視頻的展現效果中能夠更好的看出它們之間的差別:
Demo: https://codepen.io/airen/full/mdWyOOj
CSS 蒙層和剪切
Demo: https://codepen.io/airen/full/MdQrvR
h1 { mask-image: url(mask.png);}複製代碼
並且咱們還能夠藉助 mask 的合成能力,讓多個蒙層作合成運算:
運用蒙層相關的能力,能夠快速幫助咱們實現一些業務場景所需的效果:
除此以外還能夠實現換膚的效果:
Demo: https://codepen.io/airen/full/yWvzYy
好比在實際需求中,須要實現一些不規則,又是多狀態下的 UI 效果,那麼 clip-path 就會很方便:
並且使用clip-path 結合 transition 或 animation 能夠在交互上作一些更好的動效:
Demo: https://codepen.io/airen/full/zYqbgRK
特別是,當clip-path 支持 path() 函數時,能夠作得事情更多了,好比咱們想要繪製一個心形的 UI 效果:
另外就是把 clip-path 、float 和 CSS 的 Shapes 結合能夠實現一些不規則的圖文混排的佈局效果:
CSS 混合模式
CSS 混合模式是個頗有意思的特性,目前主要有 mix-blend-mode 和 background-blend-mode 兩個屬性,前者是用於多個元素的合成,後者是用於多個背景的合成。使用它們能夠實現一些特殊的效果,好比相似 Photoshop 中的濾鏡效果:
採用混合模式特性,咱們能夠輕易的實現產品圖換色的效果:
Demo: https://codepen.io/kylewetton/full/OJLmJoV
這裏簡單地介紹一下,這個效果是怎麼實現的。
首先咱們有一張相似下圖的產品圖:
經過 SVG 的能力,咱們描繪圖一個純黑色的 SVG 形狀,形狀和上圖的沙發是相吻合的:
描繪出來的 SVG 代碼並不複雜:
<svg id="js-couch" class="couch__overlay" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="none" width="1000" height="394"> <defs> <path d="M996.35 77.55q-1.85-1.95-8.65-3.75l-62.4-17.1q-9.3-2.75-12.15-2.5-1.8.15-2.85.45l-.75.3q2.25-16.3 3.75-22.05 1.15-4.4 1.4-10.8.2-6.6-.7-10.85-1.25-5.65-3.1-7.8-2.95-3.35-9.65-2.7-5.95.6-39.3 1.7-38.3 1.25-39.45 1.3-10.25.5-126.75.5-5.05 0-54.2 1.3-45.8 1.25-54.05.95-19.45-.45-30.4-.7-20.2-.55-23.1-1.3-22.3-5.85-26.5 1.25-2.65 4.55-3.85 7.9-.6 1.7-.7 2.5-.65-2.2-2.05-4.55-2.75-4.65-6.45-5.2-3.85-.55-13.65-.4-7.4.1-12 .4-.4.05-18.7.9-16.55.8-19.15 1.1-3.4.4-14.6 1.1-11.3.75-13.05.65h-9.8q-8.65-.05-11.45-.4-2.85-.35-9.25-.6-6.7-.15-8.5-.25-2.7-.1-27.75-.1-25.1 0-29.6.1-92.35 1.15-99 1.65-5.15.4-20 0-15.3-.4-24.4-1.25-6.75-.6-21-1.55-12.95-.9-14.85-1.1-6.45-1.05-11.05-1.5-8.7-.85-12.85.5-5.45 1.75-8.1 4.65-3.2 3.4-2.9 8.6.25 4.65 2.1 11.8 1 3.8 2.55 9.1 1 3.85 2.35 10.1-.1 1-1.5 1-1.75 0-7.7.85-7.1 1-9.8 2.05-2.4.9-23 4.75-21.2 3.9-22.05 4.15-8.2 1.85-15.05 3.35Q7.4 69.1 5.65 70.3 2.5 72.45 2 73.1.6 75 .75 79.2q.15 4.15 1.3 12.75.9 6.85 1.45 10 .5 2.75 8.55 54 6.65 42.15 7.35 46.85 1.15 7.65 4.9 28.55 4.55 25.2 6.35 31.2 2.45 8.15 3.8 11.75 1.85 4.9 3.2 5.75 1.25.8 6.85.65 2.75-.05 5.3-.25l23.85.35q.1 0 1 .95t2 .95q1.9 0 3.4-1.4l23.1-.25 43.65.4q135.05 2.15 137.9 1.9 1.25-.1 72.9.5 72.45.65 76.85.45 8.1-.35 64 .4 143.35.95 146 1.1.55.05 75.3.3 74.7.3 79.8.6 8.65.5 68.25-.35l51.75.5 1.6.4q1.95.35 3.8.05 1.45-.25 3.5-.2 1.9 0 3.35-.3 2.1-.45 8.25-.8 6.25-.3 8.75-.05 1.7.2 8 1 5.75.3 7.4-1.75 1.75-2.2 4.95-10.85 2.8-7.55 4.05-12.4.65-2.5 3.6-17.2 2.75-13.75 3.15-14.8.45-1.25 4.45-22.85 4.05-22.4 4.4-24.4.3-1.45 3.75-25.2 3.35-23.2 4-26.3 1.15-5.5 2.35-18.8 1.4-15.7.8-23.7-.6-8.35-3.35-11.15z" id="a" /> </defs> <use xlink:href="#a"/> </svg>
使用 CSS 自定義屬性,配合少量的 JavaScript代碼便可完成產品圖換色的效果:
:root { --fill: #f36;}
svg { fill: var(--fill); mix-blend-mode: multiply;}
咱們使用 mix-blend-mode 的 multiply 效果。另外,JavaScript 動態改變 --fill 的值代碼也簡單:
const inputEle = document.querySelector('input')
inputEle.addEventListener('change', (e)=>{ document.documentElement.style.setProperty('--fill', e.target.value); })複製代碼
很簡單吧,並且你能夠發揮你的想象空間,能夠實現不少具備創意的效果。
CSS 自定義屬性
CSS 自定義屬性能夠說是 CSS 的標配了,正如 W3C 規範所描述的,CSS 自定義屬性又被稱爲 CSS 變量:
不過在這裏要說的不是 CSS 自定義如何使用?要和你們說的是 CSS 自定義屬性中的無效變量。CSS 自定義屬性中的無效變量是頗有用的一個特性,它能夠實現 1 (真)和 0 (假)的開關切換效果。換句話說,能夠很好的實現不一樣狀態的 UI 效果。
一樣地,在 W3C 規範中對無效變量有詳細描述,但不仔細的話,仍是會忽略該特性。先來看規範是怎麼描述無效變量的:
它的意思是:
當一個自定義屬性的值是
**initial**
時,**var()**
** 函數不能使用它進行替換。除非 指定了一個有效的回退值,不然會使聲明在計算值時無效。**
在 CSS 中註冊自定義屬性時是使用 -- 來註冊的,能夠給已註冊的自定義屬性賦值,包括空字符串,但其中有一個細節很是有意思:
:root { --invalid:; // 注意冒號和分號之間無空格符,也無任何字符 --valid: ; // 注意冒號和分號之間只有一個空格符}
其中,--invalid 自定義屬性被稱爲無效變量,而 --valid 自定義屬性是一個有效變量。使用上面這種方式來區分有效和無效變量對於開發者而言,可讀性極差,並且有些文本編輯器可能會對代碼按本身配置的規格格式化,有可能會形成 --invalid:; 變成 --invalid: ; (有空格)。爲此,通常使用關鍵詞 initial來顯式聲明一個自定義屬性爲無效變量:
:root { --invalid: initial; // 無效變量 --valid: ; // 有效變量}
若是不使用 var() 函數調用已註冊的自定義屬性的話,那麼對於已註冊的自定義屬性而言,不會起任何做用。而 var() 函數有兩個參數,第一個參數就是自定義屬性,第二個參數是備用值。當第一個參數是個無效值時,會採用第二個參數。正因如此,對於已註冊的無效自定義屬性(即無效變量),好比 上面代碼中的 --invalid 。那麼 var() 沒有提供備用值(第二個參數),則會使 CSS 樣式規則(聲明)在計算值時無效:
:root { --invalid: initial; // 無效變量 --valid: ; // 有效變量}
foo { background-color: var(--invalid); // 未提供備用值,則background-color 計算值無效 color: var(--invalid, red) // 提供了備用值,--invalid是無效變量,則會採用備用值 red}
先來看一個簡單的示例:
<div class="element"> <i>Element</i></div>
<i>Element</i>
<style> .element { --color: red; // 只做用於 .element 元素及其後代元素 }
i { --foo: initial; // 無效變量 --color: var(--foo); // 無效變量 background-color: var(--color, orange); // --color是無效變量,採用備用值 orange }</style>
運行上面的代碼,你將看到的效果以下圖所示:
Demo: https://codepen.io/airen/full/GRWJGvx
再來看另外一個示例:
<section>Element</section>
<style> :root { --initial: initial; // 無效變量 --valid: ; // 有效變量 } section { background-color: var(--initial, red); // 無效變量,會採用備用值 red color: var(--valid, red); // 有效變量,備用值被忽略 }</style>
所以,你看到的效果以下:
Demo: https://codepen.io/airen/full/poeJKpM
:root { --ON: initial; // 無效變量,至關於開啓 var()的備用值 --OFF:; // 有效變量,至關於關閉 var()的備用值}
這樣一來,咱們在作 UI 不一樣狀態切換時,就只須要對 --ON 和 --OFF 的切換。好比某篇文章中提供的示例:
:root { --ON: initial; --OFF: ;}
button { --is-raised: var(--OFF); border: 1px solid var(--is-raised, rgb(0 0 0 / 0.1)); background: var( --is-raised, linear-gradient(hsl(0 0% 100% / 0.3), transparent) ) hsl(200 100% 50%); box-shadow: var( --is-raised, 0 1px hsl(0 0% 100% / 0.8) inset, 0 0.1em 0.1em -0.1em rgb(0 0 0 / 0.2) ); text-shadow: var(--is-raised, 0 -1px 1px rgb(0 0 0 / 0.3));}
button:hover { --is-raised: var(--ON);}
button:active { box-shadow: var(--is-raised, 0 1px 0.2em black inset);}
最終效果以下:
Demo: https://codepen.io/airen/full/XWNYRga
上面這個示例算是簡單的了。不過咱們能夠利用該特性實現更復雜的 UI 效果。好比下面這個多種換膚效果:
label { --box-shadow: var(--ON); --box-shadow-active: var(--OFF); box-shadow: 0 0 0 3px var(--box-shadow, rgba(0, 0, 0, 0.05)) va r(--box-shadow-active, #2196f3); cursor: pointer;}
label.dark { background-color: var(--dark-bgcolor);}
label.light { background-color: var(--light-bgcolor);}
label.blue { background-color: var(--blue-bgcolor);}
#dark:checked ~ div .dark,#light:checked ~ div .light,#blue:checked ~ div .blue { --box-shadow: var(--OFF); --box-shadow-active: var(--ON);}
.nav { color: var(--light, var(--light-color)) var(--dark, var(--dark-color)) var(--blue, var(--blue-color)); background-color: var(--light, var(--light-bgcolor)) var(--dark, var(--dark-bgcolor)) var(--blue, var(--blue-bgcolor));}
a.active,a:hover { background-color: var(--light, var(--light-active-bgcolor)) var(--dark, var(--dark-active-bgcolor)) var(--blue, var(--blue-active-bgcolor));}
/* 設置切換開關 */:root { --ON: initial; --OFF: ;
/* Dark */ --dark-color: rgba(156, 163, 175, 1); --dark-bgcolor: rgba(17, 24, 39, 1); --dark-active-bgcolor: rgba(55, 65, 81, 1);
/* Light */ --light-color: rgba(55, 65, 81, 1); --light-bgcolor: rgba(243, 244, 246, 1); --light-active-bgcolor: rgba(209, 213, 219, 1);
/* Blue */ --blue-color: rgba(165, 180, 252, 1); --blue-bgcolor: rgba(49, 46, 129, 1); --blue-active-bgcolor: rgba(67, 56, 202, 1);}
#dark:checked ~ .nav { --light: var(--OFF); --dark: var(--ON); --blue: var(--OFF);}
/* 默認爲Light */#light:checked ~ .nav { --light: var(--ON); --dark: var(--OFF); --blue: var(--OFF);}
#blue:checked ~ .nav { --light: var(--OFF); --dark: var(--OFF); --blue: var(--ON);}
效果以下:
Demo: https://codepen.io/airen/full/OJbEzzw
示例中沒有使用任何 JavaScript 代碼。是否是頗有意思。要是感興趣的話,你也能夠嘗試着擼擼這樣的效果。
因爲篇幅緣由,本文只介紹部分屬性,剩餘部分請期待下期的《詳解16個 CSS 新特性(2021最新版-下)》。
✿ 拓展閱讀
本文分享自微信公衆號 - 淘系技術(AlibabaMTT)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。