2023 年 CSS 新特性大盤點
全文概覽:
- 基礎功能
- 三角函數
- 復雜的nth-*選擇器
- @scope
- 嵌套
- 子網格
- 排版
- Initial-letter
- text-wrap
- 顏色
- 高級色彩空間
- color-mix 函數
- 相對顏色語法
- 響應式設計
- 容器大小查詢
- 容器樣式查詢
- :has() 選擇器
- 更新媒體查詢
- 腳本媒體查詢
- 交互
- 視圖轉換
- 線性緩動函數
- 滾動結束
- 滾動驅動動畫
- timeline-scope
- 離散屬性動畫
- @starting-style
- overlay
- 組件
- Popover
- 選擇框中的分隔線
- :user-valid 和 :user-invalid
- 獨占式手風琴
基礎功能
首先來了解一下核心 CSS 語言和功能的更新。
三角函數
Chrome 111 增加了對三角函數 sin()、cos()、tan()、asin()、acos()、atan() 和 atan2() 的支持,使其適用于所有主流引擎。這些函數對于動畫和布局來說非常有用。例如,現在可以更輕松地在以所選中心為中心的圓圈上布置元素。
瀏覽器支持:
復雜的nth-*選擇器
借助:nth-child()偽類選擇器,可以按索引選擇 DOM 中的元素。可以使用 An+B 微語法精確控制要選擇哪些元素。
默認情況下,:nth-*()偽類會考慮所有子元素。從 Chrome 111 開始,可以選擇將選擇器列表傳遞給:nth-child()和:nth-last-child()。這樣就可以在 An+B 執行操作之前預先過濾子項列表。
在下面的演示中,通過使用 of .small 對小玩偶進行預過濾,3n+1 邏輯僅應用于它們。使用下拉菜單可動態更改所使用的選擇器。
瀏覽器支持:
@scope
Chrome 118 增加了對 @scope 的支持,它可以將選擇器的范圍限定為文檔的特定子樹。借助作用域樣式,可以非常具體地選擇元素,而無需編寫過于具體的選擇器或將它們與 DOM 結構緊密耦合。
限定作用域的子樹由作用域根和可選的作用域限制定義。
@scope (.card) { … } /* scoping root */
@scope (.card) to (.card__content) { … } /* scoping root + scoping limit*/
放置在作用域塊內的樣式規則僅針對劃分出的子樹中的元素。例如,以下作用域樣式規則僅針對位于.card元素和由[data-component]選擇器匹配的任何嵌套組件之間的<img>元素。
@scope (.card) to ([data-component]) {
img { … }
}
瀏覽器支持:
嵌套
在 CSS 原生支持嵌套之前,每個選擇器都需要單獨顯式地聲明。這會導致重復、樣式表龐大和分散的作者體驗。現在,選擇器可以繼續并將相關的樣式規則分組在一起。
dl {
/* dt */
dt {
/* dl dt */
}
dd {
/* dl dd */
}
}
dt {
/* dt */
}
dl dt {
/* dl dt */
}
dl dd {
/* dl dd */
}
嵌套可以減少樣式表的大小,減少重復選擇器的開銷,并集中組件樣式。最初發布的語法有一個限制,需要在各個地方使用 &
,但自那時起,隨著嵌套語法的放寬更新,這一限制已經被解除。
瀏覽器支持:
子網格
借助 CSS subgrid 可以創建更復雜的網格,并在子布局之間實現更好的對齊。它允許內部網格采用外部網格的行和列作為自己的行和列,通過在網格行或列中使用subgrid作為值。
子網格特別適用于將兄弟元素對齊到彼此的動態內容。
瀏覽器支持:
排版
2023 年,網頁排版取得了一些重要更新。其中一個特別好的漸進增強是text-wrap屬性,該屬性可以在瀏覽器中進行排版布局調整,而無需額外的腳本。告別尷尬的行長度,體驗更具可預測性的排版!
Initial-letter
在 2023 年初的 Chrome 110 中引入的initial-letter屬性是一個小而強大的CSS功能,它用于設置首字母的排版樣式。可以將字母放置在下沉或抬高的狀態下。該屬性接受兩個參數:第一個參數用于控制字母下沉到相應段落的深度,第二個參數用于將字母抬高多少,可以同時使用這兩個參數。
p {
font-size: 2rem;
max-width: 36ch;
color: var(--tangerine);
background: white;
&::first-letter {
initial-letter: 3 2;
font-weight: 800;
padding-right: 1rem;
background: linear-gradient(
to right,
var(--razzmatazz),
var(--goldenyellow)
);
color: transparent;
-webkit-background-clip: text;
}
}
效果如下:
瀏覽器支持:
text-wrap
作為開發人員,我們可能無法確定標題或段落的最終大小、字體大小,甚至語言。瀏覽器提供了所有文本換行所需的變量,這些變量對于有效和美觀的文本處理非常重要。由于瀏覽器了解所有因素,比如字體大小、語言和分配的區域,它成為處理高級和高質量文本布局的絕佳選擇。
這就是兩種全新的文本換行技術發揮作用的時刻,它們被命名為balance和pretty。balance值的目的是創建和諧的文本塊,而pretty則致力于防止孤立的字符并確保連字符的健康使用。在過去,這兩項任務通常需要手動完成,但現在可以將它們交給瀏覽器來處理,并使其適應任何翻譯語言。
顏色
2023 年是 Web 平臺的色彩革新之年。借助全新的色彩空間和功能,實現了動態色彩主題,可以為用戶打造更生動、豐富的主題,并且還可以實現個性化定制!
高級色彩空間
在 2023 年,我們擁有了全新的顏色、更多的顏色、新的色彩空間、色彩函數和新的功能。
現在,CSS 和顏色可以做到以下事情:
- 檢查用戶屏幕硬件是否支持廣色域HDR顏色。
- 檢查用戶的瀏覽器是否理解如Oklch或Display P3等顏色語法。
- 在Oklab、Oklch、HWB、Display P3、Rec.2020、XYZ等多種格式中指定HDR顏色。
- 創建具有HDR顏色的漸變。
- 在可選顏色空間中插值漸變。
- 使用color-mix()混合顏色。
- 利用相對顏色語法創建顏色變體。
color-mix 函數
通過 color-mix 函數僅可以混合白色或黑色到一種顏色,還可以混合透明度,并且可以在選擇的任何顏色空間中完成所有這些操作,它同時具有基本顏色特性和高級顏色特性。
可以將color-mix()視為漸變過程中的一個時間點,該漸變展示了從藍色到白色的所有中間步驟,而color-mix()僅展示了其中的一個步驟。
瀏覽器支持:
相對顏色語法
相對顏色語法是與color-mix()相輔相成的一種方法,用于創建顏色變體。它比color-mix()更強大,但也是一種不同于傳統顏色處理的策略。color-mix()可以混入白色以減輕顏色的深淺程度,而相對顏色語法則提供了對亮度通道的精確訪問,并可以利用calc()函數以編程方式降低或增加亮度。
相對顏色語法允許對顏色進行相對和絕對的操作。相對變化是指使用calc()函數對飽和度或亮度的當前值進行修改。絕對變化是指將通道值替換為全新的值,例如將不透明度設置為50%。這種語法為各種主題和實時變體提供了實用的工具。
響應式設計
2023 年,響應式設計邁向了新的高度。這一具有里程碑意義的年份帶來了創新的功能,顛覆了傳統的構建響應式網頁體驗的方式,并引領了基于組件的響應式設計模型的新潮流。容器查詢和:has()的完美結合,使得組件能夠根據其父元素的大小以及任何子元素的存在或狀態,靈活地適應并展現出相應的樣式。這意味著我們現在可以將頁面級的布局與組件級的布局分離開來,并且只需編寫一次邏輯,便可以在任何地方重復使用組件!
容器大小查詢
與使用視口的全局大小信息來應用CSS樣式不同,容器查詢支持在頁面內查詢父元素。這意味著組件可以以動態方式在多個布局和多個視圖中進行樣式設置。2月14日,所有現代瀏覽器都穩定支持了容器大小查詢。
要使用此功能,首先在要查詢的元素上設置容器,然后類似于媒體查詢,使用@container和大小參數來應用樣式。除了容器查詢,還可以獲得容器查詢的大小。在以下示例中,容器查詢大小cqi(表示內聯容器的大小)用于調整卡片標題的大小。
瀏覽器支持:
容器樣式查詢
在 Chrome 111 中,樣式查詢以部分實現的形式出現。借助樣式查詢功能,可以在使用@container style()
時查詢父元素上自定義屬性的值。例如,檢查自定義屬性是否存在,或者是否被設置為特定值,如@container style(--rain: true)
。
盡管樣式查詢在某種程度上與在CSS中使用類名相似,但樣式查詢具有其獨特的優勢。首先,使用樣式查詢,可以在CSS中根據需要更新偽狀態的值。此外,未來的版本將支持查詢數值范圍來確定應用的樣式,例如style(60 <= --weather <= 70),并且可以基于屬性-值對設置樣式,例如style(font-style: italic)。
瀏覽器支持:
:has() 選擇器
在過去的20年里,開發者們一直期待在CSS中加入“父選擇器”。隨著在 Chrome 105 中引入:has()選擇器,這一愿望終于得以實現。例如,使用.card:has(img.hero)將選擇那些包含英雄圖像子元素的.card元素。
.card:has(.card__media) {
grid-template-areas:
"title"
"blurb"
"author"
"media";
padding-bottom: 0;
--color: #6300ff;
}
由于:has()接受一個相對選擇器列表作為參數,因此可以選擇多個元素,不僅可以沿著DOM樹向上選擇,還可以進行橫向選擇。例如,li:has(+ li:hover)將選擇當前鼠標懸停的<li>元素之前的<li>元素。
瀏覽器支持:
更新媒體查詢
更新媒體查詢提供了一種根據設備刷新率來調整用戶界面的方法。這個功能可以報告設備的刷新率是快速、慢速還是根本沒有刷新率,這與不同設備的能力密切相關。
大部分設備可能都具備較快的刷新率,包括臺式機和大多數的移動設備。然而,一些設備如電子閱讀器和低功耗支付系統等可能具備較慢的刷新率。了解到設備無法處理動畫或頻繁更新的情況,意味著可以更加合理地使用電池,或者避免因為頻繁的視圖更新而導致的故障。
腳本媒體查詢
媒體查詢腳本可以用于檢查JavaScript是否可用,這對漸進增強非常有用。在引入這個媒體查詢之前,檢測JavaScript是否可用的策略是在HTML中放置一個nojs類,并使用JavaScript將其移除。現在,由于CSS有了一種檢測JavaScript并相應調整的方式,因此可以移除這些腳本。
通過使用腳本媒體查詢,可以在沒有JavaScript可用的情況下,根據系統偏好進行網站主題的切換。此外,還可以考慮一個切換組件,當JavaScript可用時,該組件可以使用手勢滑動進行切換,而不僅僅是簡單地切換開關的狀態。這樣,在腳本可用的情況下,可以提供更優化的用戶體驗;而在腳本禁用的情況下,仍然能夠提供基本而有意義的體驗。
交互
今年,有許多令人振奮的交互功能陸續問世,這些功能使得交互的構建和實施變得更加簡單,從而促進了流暢的用戶體驗和更加精致的網絡體驗。
視圖轉換
通過使用視圖轉換API,可以在單頁應用的兩個頁面狀態之間創建視覺轉換。這些轉換可以是全頁面轉換,也可以是頁面上的小元素,例如添加或刪除列表中的新項目。
視圖轉換API的核心是document.startViewTranstion函數。只需傳遞一個更新DOM到新狀態的函數,API就會處理所有細節。它通過獲取先前和后續快照,然后在兩者之間進行過渡來實現這一點。可以使用CSS來控制要捕獲的內容,并可選擇自定義這些快照的動畫方式。
瀏覽器支持:
線性緩動函數
線性緩動函數是用于動畫效果的一種函數,它并非真正的“線性”(linear)函數,而是一種簡化的緩動函數,可以模擬更復雜的動畫效果。盡管這種函數的精度可能略有降低,但它的實現方式簡單直觀,可以方便地應用于各種動畫效果。
在 Chrome 113 版本之前,CSS中確實無法直接創建反彈或彈簧等復雜的動畫效果。然而,通過使用linear()函數,開發者可以將這些復雜的緩動效果簡化為一系列的點,然后在這這些點之間進行線性插值,從而得到一種近似的緩動效果。
原始的藍色反彈曲線被簡化為一組綠色關鍵點,linear()函數使用這些關鍵點,并在它們之間進行線性插值。
瀏覽器支持:
滾動結束
許多界面都包含滾動交互,有時界面需要同步與當前滾動位置相關的信息,或者根據當前狀態獲取數據。在scrollend事件之前,開發者們通常采用設置超時的方式來嘗試捕捉滾動動作的結束。這種做法并不準確,因為超時可能會在用戶手指仍然觸摸屏幕時被觸發。這可能導致用戶體驗的不連貫,或者獲取到不準確的數據。
現在,有了scrollend事件,開發者可以獲得一個更加精準定時的方式。scrollend事件能夠在用戶滾動動作結束時立即觸發,從而判斷用戶是否仍處于手勢的中間狀態。
瀏覽器支持:
滾動驅動動畫
從 Chrome 115 版本開始,滾動驅動的動畫成為了一項令人振奮的功能。這項功能可以將現有的CSS動畫或使用Web動畫API構建的動畫與滾動容器的滾動偏移量相結合。當上下滾動(或在水平滾動容器中左右滾動)時,鏈接的動畫會直接響應地前后播放。
通過使用ScrollTimeline,可以跟蹤滾動容器的總體進度。例如,下面的演示顯示了當滾動到頁面末尾時,文本逐個字符地顯示出來。這一優化確保了流暢、連貫的用戶體驗,同時允許開發者利用瀏覽器的內置功能來實現復雜的效果。
使用 ViewTimeline 可以跟蹤一個元素在滾動視口中的位置。這類似于IntersectionObserver跟蹤一個元素的方式。在下面的演示中,每個圖像從進入滾動視口開始逐漸顯示,直到位于中心位置。
滾動驅動的動畫與CSS動畫和Web動畫API的結合,可以使開發者受益于這些API帶來的所有優勢。其中最顯著的優勢之一是能夠在主線程之外運行動畫。通過添加幾行額外的代碼,開發者可以讓由滾動驅動的動畫在主線程之外順暢運行,從而避免阻塞主線程,提高應用的響應性和性能。
瀏覽器支持:
timeline-scope
在通過CSS應用滾動驅動的動畫時,查找控制滾動的機制總是沿著DOM樹向上查找,這使得它僅限于滾動祖先。然而,很多時候,需要動畫的元素并不是滾動容器的子元素,而是位于完全不同的子樹中的元素。
為了使動畫元素能夠找到非祖先元素的命名滾動時間線,可以在共享父元素上使用timeline-scope屬性。這將允許具有該名稱的定義的scroll-timeline 或 view-timeline附加到該元素,使其具有更廣泛的范圍。有了這個功能,任何共享父元素的子元素都可以使用具有該名稱的時間線。
在共享父元素上聲明timeline-scope后,滾動容器上聲明的滾動時間線可以被使用它作為其動畫時間線的元素找到。
瀏覽器支持:
離散屬性動畫
2023年的另一個新功能是對離散動畫進行動畫處理的能力。離散動畫是指屬性值在兩個或更多離散值之間變化的動畫,例如從display: none到可見狀態的動畫。從Chrome 116開始,可以在關鍵幀規則中使用display和content-visibility屬性,并在動畫的50%位置而不是0%位置過渡任何離散屬性。
這個優化方法通過使用transition-behavior屬性中的allow-discrete關鍵字或在transition屬性中作為簡寫來實現。這使得開發者可以更靈活地控制離散屬性的動畫過渡,并在需要時實現更平滑的過渡效果。
瀏覽器支持:
@starting-style
通過使用@starting-style CSS規則,可以對display: none進行動畫處理。該規則提供了一種在元素打開之前,瀏覽器可以查找的“打開前”樣式的方式。這對于創建入場動畫以及顯示諸如彈出框或對話框等元素非常有用。同時,它還可以用于在創建新元素并希望為其添加動畫效果時。
下面的例子將一個彈出框平滑地從視口外部動畫顯示到頂層:
@starting-style {
dialog[open] {
translate: 0 100vh;
}
}
瀏覽器支持:
overlay
通過使用新的 CSS overlay 屬性,可以添加過渡效果,使具有頂層樣式的元素(例如彈出框、對話框等)能夠平滑地從頂層動畫移出。如果沒有使用過渡到overlay,元素將立即回到被裁剪、變形和覆蓋的狀態,導致看不到轉換發生的過程。類似地,當在頂層元素上添加overlay屬性時,它可以使得::backdrop元素能夠平滑地動畫移出。
瀏覽器支持:
組件
2023年對于樣式和HTML組件來說是重要的一年,其中引入了彈出框功能,并對錨點定位和下拉菜單樣式進行了大量的改進。這些組件使得構建常見的UI模式更加容易,無需依賴額外的庫或每次都從頭開始構建自己的狀態管理系統。
Popover
Popover API 可以幫助開發者構建覆蓋在頁面上方的元素,這些元素可能包括菜單、選擇和工具提示。通過為彈出的元素添加popover屬性和id,并將其id屬性與觸發按鈕連接起來,使用popovertarget="my-popover"可以創建一個簡單的彈出框。Popover API 具有以下優點:
- 提升到頂層:彈出框將顯示在頁面其余部分的上方,因此無需修改z-index。
- 輕松關閉功能:單擊彈出框區域之外會關閉彈出框并返回焦點。
- 默認焦點管理:打開彈出框會使下一個tab停留在彈出框內。
- 可訪問的鍵綁定:按下esc鍵或雙倍切換將關閉彈出框并返回焦點。
- 可訪問的組件綁定:將彈出框元素與彈出框觸發器語義化地連接。
<div popover role="menu" id="menu">
<button class="close-btn" popovertarget="menu" popovertargetaction="hide">
<span>?</span>
<span class="sr-only">Close</span>
</button>
<ul>
<li><a href="#">Typography</a></li>
<li><a href="#">Foundations</a></li>
<li><a href="#">Color</a></li>
<li><a href="#">Interactions</a></li>
<li><a href="#">Components</a></li>
<li><a href="#">Responsive</a></li>
</ul>
</div>
瀏覽器支持:
選擇框中的分隔線
今年在Chrome和Safari中引入的另一個HTML的小改變是,現在可以在<select>元素中添加水平線元素(<hr>標簽),以幫助視覺上分隔內容。以前,在<select>中放置<hr>標簽不會被渲染。但今年,Safari和Chrome都支持此功能,可以更好地在<select>元素中分隔內容。
<select name="majors" id="major-select">
<option value="">Select a favorite feature</option>
<hr>
<optgroup label="Foundations">
<option value="trig">Trigonometric functions</option>
<option value="nth">Complex nth-* selection</option>
<option value="nesting">Nesting</option>
<option value="subgrid">Subgrid</option>
<option value="mq-ranges">Media query range syntax</option>
</optgroup>
<optgroup label="Typography">
<option value="initial-letter">Initial-letter</option>
<option value="text-wrap-b-p">Text-wrap: balance / pretty</option>
</optgroup>
<optgroup label="Color">
<option value="color-4">CSS Color level 4</option>
<option value="color-mix">Color-mix function</option>
<option value="rcs">Relative color syntax</option>
</optgroup>
<optgroup label="Responsive Design">
<option value="cq">Size container queries</option>
<option value="sq">Style container queries</option>
<option value="has">:has() selector</option>
</optgroup>
</select>
:user-valid 和 :user-invalid
今年所有瀏覽器均穩定支持 :user-valid 和 :user-invalid 偽類,它們的行為類似于 :valid 和 :invalid 偽類,但只有在用戶與輸入進行了重要交互之后,才匹配表單控件。即使用戶尚未開始與頁面進行交互,必填但是空的表單控件將匹配 :invalid。只有當用戶更改輸入并將其保留在無效狀態時,該控件才會匹配 :user-invalid。
有了這些新的選擇器,就不再需要編寫有狀態的代碼來跟蹤用戶已更改的輸入。
input:user-valid,
select:user-valid,
textarea:user-valid {
--state-color: green;
--bg: linear-gradient(45deg in oklch, lime, #02c3ff);
}
input:user-invalid,
select:user-invalid,
textarea:user-invalid {
--state-color: red;
--bg: linear-gradient(15deg in oklch, #ea00ff, #ffb472);
}
瀏覽器支持:
獨占式手風琴
Web上常見的UI模式之一是手風琴組件。要實現此模式,通常需要將幾個<details>元素組合在一起,通過視覺分組來表明它們之間的聯系。
在 Chrome 120 中,引入了一項新功能,即在<details>元素上支持name屬性。使用這個屬性時,具有相同名稱值的多個<details>元素會形成一個語義組合。該組合中最多只能打開一個元素:當打開該組合中的一個**<details>**元素時,之前打開的一個將自動關閉,這種手風琴稱為獨占式手風琴。
<details name="my-accordion">
<summary>Summary 1</summary>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptas delectus quibusdam, eum, aperiam sunt non dolorum pariatur molestias suscipit aut quia quas vero, illo quisquam nostrum sequi excepturi. Aliquam, obcaecati?</p>
</details>
<details name="my-accordion" open>
<summary>Summary 2</summary>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptas delectus quibusdam, eum, aperiam sunt non dolorum pariatur molestias suscipit aut quia quas vero, illo quisquam nostrum sequi excepturi. Aliquam, obcaecati?</p>
</details>
<details name="my-accordion">
<summary>Summary 3</summary>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptas delectus quibusdam, eum, aperiam sunt non dolorum pariatur molestias suscipit aut quia quas vero, illo quisquam nostrum sequi excepturi. Aliquam, obcaecati?</p>
</details>
作為獨占式手風琴的一部分的<details>元素不一定需要是兄弟元素,它們可以散布在文檔任意位置。