2024 年你可以安全地使用哪些 CSS 新特性?
在過去的 4 年中,大量的 CSS 新特性涌現(xiàn)。不過對能在瀏覽器中安全使用的 CSS 特性我們要甄別,不然學(xué)過之后發(fā)現(xiàn)兼容性差得不行,那就有點(diǎn)得不償失了。
這里總結(jié)了你可以在 2024 年可以安全使用的 CSS 特性。
1、CSS 邏輯屬性
圖片
兼容性:https://caniuse.com/css-logical-props
長期以來,許多 CSS 屬性使用物理方向來設(shè)置值,如margin-top、padding-right、bottom、border-left 等。但在國際化(多語言環(huán)境)背景下,基于物理方位的設(shè)置無法適應(yīng)不同書寫模式下(writing-mode)一致的閱讀、布局體驗(yàn),于是便有了基于 Inline、Block 概念的邏輯屬性(Logical properties)。
width: 40px; --> inline-size: 40px;
height: 20px; --> block-size: 20px;
margin-top: 12px; --> margin-block-start: 12px;
margin-bottom: 12px; --> margin-block-end: 12px;
margin-left: 14px; --> margin-inline-start: 14px;
margin-right: 14px; --> margin-inline-end: 14px;
margin-top: 12px; margin-bottom: 16px; --> margin-block: 12px 16px;
margin-left: 16px; margin-right: 16px; --> marign-inline: 16px;
2、容器查詢
圖片
兼容性:https://caniuse.com/css-container-queries
容器查詢(Container queries)與媒體查詢(Media queries)類似,不過媒體查詢只支持使用瀏覽器寬度或高度作為查詢條件,但容器查詢則適用于任何容器,而不僅僅是瀏覽器。
容器查詢根據(jù)功能又可以拆分成尺寸查詢(Size Queries)和樣式查詢(Style Queries),其中樣式查詢支持有限,因此目前當(dāng)我們談?wù)撊萜鞑樵儠r,實(shí)際上是指容器查詢中的尺寸查詢。
.post {
container: sidebar / inline-size;
/*等同于 container-name: sidebar; container-type: inline-size;*/
}
@container sidebar (min-width: 700px) {
.card {
font-size: 2em;
}
}
以上代碼的含義:
- 將類名為 .post 的元素聲明為名為 sidebar 的容器,inline-size 表示這個容器的查詢將基于它的內(nèi)聯(lián)尺寸(在默認(rèn)文檔流下 writing-mode: horizontal-tb;,效果等同于寬度 width)
- container sidebar (min-width: 700px) {...} 則表示當(dāng)名為 sidebar 的容器(即前面定義的 .post 元素)的內(nèi)聯(lián)尺寸(寬度)達(dá)到或超過 700p 時,其內(nèi)部 .card 的元素的字體大小設(shè)置為 2em
3、:has()
圖片
兼容性:https://caniuse.com/css-has
顧名思義,當(dāng)需要根據(jù)元素內(nèi)部是否某些特定元素來決定外部元素的樣式時,就可以使用 :has 偽類。
理解 :has() 偽類最好的方式就是通過案例學(xué)習(xí)。
案例 1:當(dāng)元素 <main> 內(nèi)包含 <strong> 標(biāo)簽時,為 <main> 應(yīng)用樣式
main:has(strong) {
/*... */
}
案例 2:當(dāng)元素 <main> 內(nèi)包含 p 和 <strong> 標(biāo)簽時,為 <main> 應(yīng)用樣式
main:has(p):has(strong) {
/*... */
}
案例 3:當(dāng)元素 <main> 內(nèi)包含 p 或 <strong> 標(biāo)簽時,為 <main> 應(yīng)用樣式
main:has(p, strong) {
/*... */
}
案例 4:當(dāng)元素 <main> 內(nèi)不含 <strong> 標(biāo)簽時,為 <main> 應(yīng)用樣式
main:not(:has(strong)) {
/*... */
}
案例 5:當(dāng)元素 <p> 后面是 <strong> 標(biāo)簽時,為 <p> 應(yīng)用樣式
p:has(+ strong) {
/*... */
}
案例 6:當(dāng)元素 <p> 后面有 <figure> 標(biāo)簽時,為 <p> 應(yīng)用樣式
p:has(~ figure) {
/*... */
}
4、:is 和 :where
圖片
:is 兼容性:https://caniuse.com/css-matches-pseudo
圖片
:where 兼容性:https://caniuse.com/mdn-css_selectors_where
:is 和 :where 功能上完全一致,接受一個選擇器列表作為參數(shù),當(dāng)列表中的任何一個選擇器匹配時,就應(yīng)用樣式。
下面的寫法是等價的:
ul li,
ol li {}
/* 等價于 */
:is(ul, ol) li {}
/* 或 */
:where(ul, ol) li {}
:is 和 :where 唯一不同之處在于,:where() 本身修改的選擇器不算在權(quán)重計(jì)算,而 :is() 修改的選擇器是算在權(quán)重計(jì)算的。
以下面的代碼舉例:
<div class="parent">
<p class="child1">Child 1</p>
<p class="child2">Child 2</p>
</div>
<style>
.parent p {
color: blue;
}
:where(p.child1,p.child2) {
color: green;
}
</style>
因?yàn)?:where 選擇器權(quán)重為 0,因此 .parent p 的樣式優(yōu)先級更高,最終文本的顏色會是藍(lán)色而不是綠色。
圖片
如果把 :where 換成 :is,文本顏色就會是綠色,因?yàn)?:is 選擇器會按照正常的選擇器優(yōu)先級規(guī)則來處理。
圖片
CSS 權(quán)重計(jì)算工具:https://specificity.keegan.st/
5、CSS 嵌套
CSS 嵌套語法(CSS Nesting)允許在一個選擇器內(nèi)部嵌套另一個選擇器,這樣可以更好地提現(xiàn) HTML 文檔元素間的結(jié)構(gòu)關(guān)系,這個語法最早是通過 SASS 這類 CSS 預(yù)處理器引入的,由于特別好用,最終成為 CSS 規(guī)范的一部分了!
圖片
兼容性:https://caniuse.com/css-nesting
Chrome 從 112 版本開始支持 CSS 嵌套[2]。
借助 CSS 嵌套,你可以在某個選擇器上下文中指定內(nèi)部元素樣式。
.parent {
color: blue;
.child {
color: red;
}
}
不過第一版本實(shí)現(xiàn)的 CSS 嵌套版本有一個限制,就是無法嵌套裸元素標(biāo)記。
.card {
h1 {
/* Chrome 112 版本中這種寫法是無效的! */
}
}
/* 要寫成帶子引用前綴 & 的 */
.card {
& h1 {
/* Chrome 112 版本中這種寫法才是有效的 */
}
}
不過,這一限制在 Chrome 120 版本中修復(fù)了[3]。
.card {
h1 {
/* Chrome 120 版本開始這種寫法是有效的! */
}
}
這是我們在使用 CSS 原生嵌套語法時,唯一要注意的地方。
6、CSS 比較函數(shù)
CSS 比較函數(shù)(Comparison Functions)類似 if/else 判斷,允許瀏覽器在你設(shè)定的多個值選擇一個合適的值應(yīng)用。這類比較函數(shù)共有 3 個:
- min(a, b):取 a 和 b 之間的最小值
- max(a, b):取 a 和 b 之間的最大值
- clamp(a, b, c) :取最小值 a、期望的值 b 和最大值 c 之間的最合適值
圖片
兼容性:https://caniuse.com/css-math-functions
min、max 相對來說比較簡單,因此我們略過直接講 clamp。
以下面一段聲明舉例:
font-size: clamp(16px, 1vw + 1rem, 32px);
字體大小會根據(jù)視口寬度和根元素字體大小進(jìn)行動態(tài)調(diào)整。
- 瀏覽器首先會嘗試使用1vw + 1rem這個計(jì)算出來的值作為字體大小
- 如果這個值小于 16px,就會使用 16px
- 如果這個值大于 32px,就會使用 32px
這種方式可以在不同的設(shè)備(如手機(jī)、平板、桌面瀏覽器)上,提供一個相對合適的、自適應(yīng)的字體大小,既保證了文本在小屏幕設(shè)備上字體足夠大,又避免了在大屏幕設(shè)備上字體過大的問題。
7、級聯(lián)層 @layer
圖片
兼容性:https://caniuse.com/css-cascade-layers
級聯(lián)層允許創(chuàng)建多個 CSS 級聯(lián)并指定級聯(lián)排序。
我們直接看案例:
<div class="overly" id="powerful">
<div class="framework widget my-single_class">widget</div>
</div>
<style>
@layer framework {
.overly#powerful .framework.widget {
color: blue;
}
}
@layer site {
.my-single_class {
color: red;
}
}
</style>
以上,我們的“widget”文本最終會呈現(xiàn)紅色。下面解釋原因:
這段代碼通過 @layer 將針對同一個元素的樣式規(guī)則劃分到了兩個不同的層 framework 和 site 中。按照 @layer 的優(yōu)先級規(guī)則,后聲明的層優(yōu)先級更高——也就是說,先看層級順序,再看同層級內(nèi)的權(quán)重。
圖片
因此,“widget”文本最終會呈現(xiàn)紅色。
當(dāng)然,你還可以通過 @layer layer1, layer2..., layerN; 指定層級應(yīng)用的順序:
圖片
可以看到,雖然書寫順序上 site 層級出現(xiàn)在 framework 之后,不過由于手動指定了層級次序:@layer site, framework;—— framework 在 site 之后,所以文本最終呈現(xiàn)藍(lán)色。
8、子網(wǎng)格
圖片
兼容性:https://caniuse.com/css-subgrid
子網(wǎng)格(Subgrid)的出現(xiàn)是為了解決傳統(tǒng)的 CSS 網(wǎng)格布局(Grid Layout)在處理多層嵌套時的對齊問題。
直接聽我說會比較抽象,我們先舉一個例子進(jìn)行說明:
<div class="wrapper">
<div class="item">
<div class="desc">short desc</div>
<img src="https://picsum.photos/id/237/200/300" alt="" class="src">
</div>
<div class="item">
<div class="desc">long desc long desc long desc</div>
<img src="https://picsum.photos/id/237/200/300" alt="" class="src">
</div>
</div>
<style>
.wrapper {
display: inline-grid;
grid-template-columns: 1fr 1fr;
grid-gap: 1rem;
}
.item {
width: 200px;
grid-row: 1 / 4;
}
</style>
效果如下:
圖片
可以看到,左右兩邊的描述文本由于長度不一樣,導(dǎo)致最終渲染出來的元素視覺上不一樣高。
這個時候,我們可以通過 subgrid 將父級網(wǎng)格行傳遞給內(nèi)部項(xiàng)目。這里需要修改 .item 元素來實(shí)現(xiàn)。
.item {
width: 200px;
grid-row: 1 / 4;
+ display: grid;
+ grid-template-rows: subgrid;
}
這里增加了 2 行,首先明確網(wǎng)格項(xiàng)目本身也是一個網(wǎng)格容器,這是子網(wǎng)格生效的前提;接著,我們將 grid-template-rows 設(shè)定成一個特殊的關(guān)鍵字 subgrid。
再來看看效果:
圖片
發(fā)現(xiàn)兩個網(wǎng)格項(xiàng)目的描述文本對齊了!
grid-template-rows: subgrid; 的作用就是讓網(wǎng)格項(xiàng)目繼承父網(wǎng)格容器的行分配系統(tǒng),或者說父子共用一套行分配系統(tǒng),這樣就能實(shí)現(xiàn)一致的對齊效果了。
更加使用案例可以參考 Ahmad Shadeed 的《Learn CSS Subgrid》[4] 這篇文章。
其他一些小而美的特性
text-wrap: balance
圖片
兼容性:https://caniuse.com/css-text-wrap-balance
text-wrap: balance 讓文本這行更好看,標(biāo)題、內(nèi)容元素皆可使用。兼容性不太好,但可以無腦用,作為漸進(jìn)式特性還是很好的。
h1, h2, h3, h4, h5, h6, blockquote {
text-wrap: balance;
}
效果:
圖片
動態(tài)視口高度 dvh
圖片
兼容性:https://caniuse.com/viewport-unit-variants
解決了 vh 單位不會考慮手機(jī)頂部地址欄、底部工具欄的問題。
圖片
詳情可以參考文章 The large, small, and dynamic viewport units[5]。
accent-color
圖片
兼容性:https://caniuse.com/mdn-css_properties_accent-color
這個屬性就比較牛了,可以用來設(shè)置某些用戶界面控件元素的強(qiáng)調(diào)色。
圖片
目前支持的元素包括單選框、復(fù)選框和進(jìn)度元素(<input type=“range|checkbox|radio”>)。
媒體查詢里的范圍查詢
圖片
兼容性:https://caniuse.com/css-media-range-syntax
范圍查詢允許我們在媒體查詢里使用使用 >、<、>= 或 <= 的數(shù)學(xué)比較運(yùn)算符。其實(shí)舊語法也支持,不過不太直觀。
我們直接舉例說明范圍查詢的使用[6]:
/* 場景一:大于等于 400px 時應(yīng)該樣式 */
/* 舊語法 */
@media (min-width: 400px) {
}
/* 新語法 */
@media (width >= 400px) {
}
/* 場景二:小于等于 30em 時應(yīng)用樣式 */
/* 舊語法 */
@media (max-width: 30em) {
}
/* 新語法 */
@media (width <= 30em) {
}
/* 場景二:在 400px、600px 之間時(包含)應(yīng)用樣式 */
/* 舊語法 */
@media (min-width: 400px) and (max-width: 600px) {
}
/* 新語法 */
@media (400px <= width <= 600px ) {
}
彈性布局 gap 屬性
圖片
兼容性:https://caniuse.com/flexbox-gap
彈性布局中的 gap 屬性可以讓我們非常便捷的設(shè)置行/列間隔,替代了古早需要通過設(shè)置 margin/padding 屬性來實(shí)現(xiàn)間隔效果的麻煩步驟。
值得注意的是,gap 屬性最先在網(wǎng)格布局(Grid Layout)和多列布局(Multi-column Layout)中實(shí)現(xiàn)(Chrome 66+),最終在彈性布局中也支持了,Chrome 84+ 兼容性足夠我們放心使用了。
參考資料
[1]New CSS that can actually be used in 2024: https://thomasorus.com/new-css-that-can-actually-be-used-in-2024.html
[2]Chrome 從 112 版本開始支持 CSS 嵌套: https://developer.chrome.com/blog/new-in-chrome-112?hl=zh-cn#nesting-rules
[3]這一限制在 Chrome 120 版本中修復(fù)了: https://developer.chrome.com/blog/css-nesting-relaxed-syntax-update?hl=zh-cn
[4]《Learn CSS Subgrid》: https://ishadeed.com/article/learn-css-subgrid/
[5]The large, small, and dynamic viewport units: https://web.dev/blog/viewport-units
[6]舉例說明范圍查詢的使用: https://web.dev/articles/media-query-range-syntax