本文由體驗技術團隊申君健原創。
序言
近日發現 Chrome 官方技術平台 chrome.dev 發佈了一篇極具價值的 CSS 技術總結文章,原文鏈接為:CSS-Wrapped-2025,Wrapped 單詞在這裏是打包,總結,回顧的意思。Chrome官方羅列了2025年的新增CSS和組件特性等,有需要的小夥伴可以關注一下。此外,Chrome 官方亦發佈了 2024 年度的 CSS 特性回顧文章,鏈接為:CSS-Wrapped-2024,可以對照查閲。
《CSS Wrapped 2025》一文共分為三個核心章節,分別是可定製的組件(Customizable Components)、 下一代交互(Next-gen Interactions)、 優化的人體工程學(Optimized ergonomics)。 由於精力時間有限,本文先精讀第一部分,有機會再分享後續部分。
2025 全年,Chrome發佈的版本為 132\~143,本文的特性也集中在這個範圍,它有很多全新的概念,或者是去年CSS概念的一些延伸。前端人員總不能第一時間使用新特性,以兼容性為藉口忽視新技術,我也是一樣。所以藉此文章中新特性為提綱,全面總結該特性的知識,補充我的一些理解和總結。同時每一個新特性還準備一句話的解釋 和 完整示例,方便大家快速瞭解。Chrome 143升級好了嗎,開始帶你飛!
一、命令調用器 (Invoker Commands)
一句話的解釋
命令調用器是通過Button元素,向Dialog,popover元素或任意元素上觸發一個動作命令。 完整示例
命令調用器特性兼具聲明式語法的高可讀性優勢,且能有效減少 JavaScript 代碼的編寫量。在該特性中,Button 元素被定義為 “命令源”,接收命令執行的元素則為 “命令目標”。
命令源:⭐僅 Button 元素才允許當命令源,它添加以下屬性:
- 【attr】commandfor: 屬性值為命令目標元素的 id,用於關聯對應的命令目標。
- 【attr】command: 用於指定點擊 Button 元素後觸發的命令動作,其屬性值説明如下:
| 命令 | 行為目標 | 等效js | 備註 |
|---|---|---|---|
| show-modal | 打開dialog | dialog.showModal() | |
| close | 關閉dialog | dialog.close() | |
| request-close | 請求關閉dialog | dialog.requestClose() | 可取消: ev.preventDefault() |
| show-popover | 打開popover | el.showPopover() | |
| hide-popover | 關閉popover | el.hidePopover() | |
| toggle-popover | 切換popover | el.togglePopover() | |
| --any-command | 自定義命令 | - | 事件名必須 -- 打頭
目標上監聽command事件 非冒泡,可取消的事件 |
- 【prop】command: 同上
- 【prop】commandForElement: 同 commandfor ,值為HTMLElement對象。
命令目標: 通常是 dialog, popover元素,為它們添加一個事件:
- 【event】command: 觸發在目標元素上的事件。 其中事件參數
event.command是命令值。
兼容性
支持chrome135+ ff144+, polyfill 方案。
總結
- 該特性的核心價值不僅在於減少 JavaScript 代碼量,更在於實現了
更好的可讀性,更好的語義化,更好的AI識別。Dialog元素是存在較久的冷門標籤,Popover API是近兩年的新特性,之前操作他們必須通過Javascript代碼。 - 該特性也是一個微型的通知系統,某些程度上可以代替
new CustomEvent的使用。同樣的,更好的可讀性,參見圖片翻轉的示例。 - 命令源只能是Button,某種程度上限制了它的使用。
二、對話框輕量關閉(Dialog Light Dismiss)
一句話的解釋
繼 Popover Api 引入 Light Dismiss 之後,Dialog 也支持了它 完整示例
Light Dismiss 直接翻譯就是輕量關閉,友好關閉,具體是指通過點擊 ::backdrop 區域、按下 Esc 鍵即可觸發目標元素自動關閉的交互行為。Light Dismiss同樣的具備聲明式可閲讀性,還能避免Javascript的使用。
<dialog closedby="none"> 不觸發關閉 </dialog>
<dialog closedby="closerequest">接受 esc或其它js觸發 </dialog>
<dialog closedby="any"> 接受任何觸發 </dialog>
Light Dismiss 通常是用户在交互過程中預期的默認行為,這一設計不僅體現了 Chrome 對用户使用體驗人體工程學的關注,更彰顯了其對開發者開發體驗人體工程學的重視。開發者無需進行額外開發,即可獲得預期的合理結果。延伸瞭解它的一些細節:
- closerequest 與 any 的相比,它不接受
點擊::backdrop區域關閉;此外移動端的手指側滑或導航回退也會觸發closerequest的行為。 - dialog.requestClose()在dialog元素上觸發
cancel 和 close事件, 而dialog.close() 只觸發close事件。 在cancel事件中執行ev.preventDefault()可阻止關閉。 - dialog元素沒有open事件,但它有
toggle, beforetoggle事件, 用來監聽打開關閉。 事件對象的oldState,newState用來判斷切換的方向。 此外,只有dialog 和 彈出層支持這2個事件名。
兼容性
支持chrome134+ ff141+, polyfill 方案。
延伸理解 Popover API 的Light Dismiss
<button popovertarget="mypopover" popovertargetaction="toggle">切換顯示</button>
<div id="mypopover" popover>這是一個 auto 彈出層</div>
命令源:⭐僅 Button 元素和Input(type=button)才允許當命令源,它添加以下屬性:
- 【attr】popovertarget: 其值為popover元素id
- 【attr】popovertargetaction: 點擊的命令動作,其值為: 'hide' | 'show' | 'toggle'
觸發popover還可以用傳統的Javascript, 或者Button的commands 模式,比如: el.showPopover()
popover層: 任意添加了 [popover] 屬性的元素
-
【attr】popover: 設置元素為一個彈出層,它最早支持以下2個值:
- auto: 自動模式,也是默認值。 auto即符合Light Dismiss默認關閉行為。同一個頁面上,auto類別的元素只能顯示一個。
- manual: 手動模式。必須顯示的聲明popovertargetaction,或調用Javascript函數才觸發,比如:el.showPopover()。同一個頁面上,manual類別元素可顯示多個。
參考完整示例,對比 Dialog 與 Popover API :
- 都支持Invoker Commands 和 Light Dismiss
- 都支持Javascript控制和聲明式表達: dialog元素的
closedby和 popover元素的popover屬性 - 都會產生一個
Top Layer, 無須z-index就能置頂元素,且不受父元素的position影響。 - 命令源和命令目標之間會隱式的產生aria-details關聯aria-expanded,用於觸發焦點導航等。
Popover API的這些特性兼容性為:chrome114+, ff125+
三、增強Popover (popover="hint") 與 興趣調用(Interest Invoker)
一句話的解釋
hint暗示:一種更輕量的觸發行為的popover類別 完整示例
在上小節中,已經講了popover原有的2個類別,今年它又新增了一個類別:hint 暗示。這種hint彈出層,不僅可以用原來的方法觸發它,還增加了一種興趣調用觸發。 興趣調用Interest Invoker是指:通過非點擊事件,比如hover,mouseover,mouseout, focus,blur 它的變化。懸浮就顯示,離開就隱藏,十分符合tooltip組件場景。
<button interestfor="mypopover1">懸浮觸發 hint1 彈出層</button>
<div id="mypopover1" popover='hint'>這是一個 hint1 彈出層</div>
命令源:它新增以下相關內容:
- 【attr】interestfor: 屬性值為 hint類別的popover元素id
- 【css-rule】interest-delay: 設置懸浮觸發和離開隱藏的時間。 它是複合屬性: interest-delay-start, interest-delay-end。默認觸發的時間是 0.5s。
- 【css-selector】 :interest-source 和 :interest-target 是指,如果當前興趣正在發生,那麼觸發源和hint 彈出層就分別為具有上面的偽類。類似於 dialog打開時,dialog:open的偽類一樣。詳見上面示例。
hint 彈出層:新增以下事件:
- 【event】interest: 觸發顯示的
InterestEvent事件, 事件的source指向觸發源元素。 - 【event】loseinterest: 離開失去的
InterestEvent事件,事件的source指向觸發源元素。
興趣調用與前面2節的內容有一些重要的差異:
- 強調必須非點擊事件,場景對應“懸而未決”的狀態,可以配合popover="hint"使用。
- 觸發源更廣泛,不僅是Button元素,還允許
<a>, <button>,<area>,SVG <a>。 - hint類別不影響auto類別的彈窗,不會主動觸發auto彈窗關閉。
長期以來Web標準對hover行為是淡視的,只有title屬性和 :hover的偽類,一直缺少關鍵的hover事件。此次提供 interest事件,藉此可以變相的視為一種hover事件
兼容性
支持chrome 142+, 不支持:ff,safari, polyfill 方案。
四、可自定義的select (Customizable select)
一句話的解釋
增強的select 和 option 元素,豐富的偽類、偽元素,定製更容易 完整示例
可定製的select增加了很多dom規範和偽類,偽元素,內容太多不宜展開細述,感興趣看上面的完整MDN示例,我已經增加詳細的註釋。此處僅列出一些重要的概念和事項,以便能快速理解:
- base-select 設置:
select 和 ::picker(select)偽元素都必須添加規則: appearance: base-select ,以區別於傳統select樣式。
- 彈出層::picker(select)特性:
它渲染在頁面頂層Top Layer,這意味着它會顯示在所有其他內容之上,不會被父容器裁剪。瀏覽器還會根據視口中的可用空間自動調整下拉列表的位置和翻轉。
- 增強的option:
傳統的option元素僅支持 label,value屬性和selected,disabled的布爾屬性。option中嵌套有其它元素,都是會忽略的。
增強後的option元素支持嵌套span,img等等普通元素,但要避免嵌套 a, input 等交互元素就行了。
- 新增 selectedcontent 元素:
該元素必須遵循 select > button > selectedcontent 的嵌套結構,詳見示例。
select的選擇值(即change事件)之後,選中的option的節點會被cloneNode創建副本,插入到selectedcontent中,所以他們結構一樣,但不是同一個元素實例。
同時button是惰性的,不響應focus等,行為更像是 div。
option 和 selectedcontent 的子項,都可以用普通的 css 選擇器去分別控制樣式。
- select 借用 Popover API
它隱式借用了非常多的Popover 特性,比如 :popover-open偽類,無需anchor-name的隱式的錨點引用,且可以定義彈出層與錨點的位置關係,溢出翻轉等等。
- select的multiple 和 optgroup 未增強
這意味着多選和分組功能,需要重新實現,對於組件庫的作者來説,這無疑得回退到傳統方案,幸好有Popover API。
兼容性:
支持 chrome 135+ , ff,safari均 不支持😭,polyfill 方案
這個方案並非真正意義的polyfill, 它使用自定義的 webComponent技術實現了平替。
五、滾動控制偽元素(::scroll-marker/button())
一句話的解釋
為滾動容器的添加偽元素,用於控制容器滾動 完整示例
HTML早早添加了dialog, detail 等元素,但一直沒有增加一個輪播圖元素,今年只摳摳搜搜添加了三個偽元素,或許是因為添加一個新元素需要考慮的事情太多。
- ::scroll-button()
滾動容器按鈕的偽元素,點擊它會觸發容器滾動。它非常類似於 ::before, ::after作用, 都需要content才顯示,且呈現在容器的內部。
每個容器最多有4個滾動方向,括號的作用是指定滾動方向,可取值:*, left,right,up,down, block-end,block-start, inline-end,inline-start等。
按鈕偽元素具有狀態,比如容器滾動到兩端之後,滾動按鈕會自動禁用。 它具有以下狀態: enabled, disabled,hover,active,focus
- ::scroll-marker 是滾動容器中,指示
滾動項的偽元素,它同樣也需要content才顯示。
它具有 :target-current 偽類, 表示滾動到當前滾動項。當然, :hover, :active等偽類也能使用
- ::scroll-marker-group 是呈現在滾動容器內部的偽元素,收集容納所有的::scroll-marker元素。
marker-group元素自身沒有高度,但可以設置邊框,佈局,間距等內容。
兼容性:
支持chrome 135+ , ff,safari均 不支持😭。由於它是css 特性,無法Polyfill, 建議使用傳統的div去實現即可!
六、設置滾動標記組容器(scroll-target-group)
一句話的解釋
設置元素為滾動容器 完整示例
CSS屬性 scroll-target-group 用來指定一個元素為滾動標記組容器, 它只有2個值:
- none: 元素非滾動標記組容器
- auto: 元素為滾動標記組容器
滾動標記組容器中通常包含錨點鏈接列表等,配合偽類 :target-current 來突出顯示某個錨點,效果非常類似傳統的Anchor組件,當容器滾動時,可以高亮指定的目錄項,不過這些都是瀏覽器自動完成的,不需要一行javascript。
它與::scroll-marker-group 有某些相似點:
- ::scroll-marker-group:是在某個元素內部,創建一個偽元素容器,用來容納::sroll-marker, 都是偽元素。
- scroll-target-group: 是把一個真實元素變為滾動容器,內部放真實的link 類元素,所以控制上會更靈活。
從官方的態度看,這2個概念極其相近,都是定義了一個滾動容器,且內部的錨點行為一致,均支持偽類 :target-current 代表高亮狀態,避免Javascript去滾動和設置高亮等。
兼容性:
支持 chrome 140+ ,但ff,safari均 不支持😭,且css 特性無法Polyfill。
七、錨定容器查詢(Anchored Container Queries)
一句話的解釋
錨點定位時,翻轉狀態可以查詢完整示例
2024年的CSS回顧中,介紹了CSS錨點定位-—— anchor positioning, 實現類似 Tooltip組件的效果,讓一個彈出層錨定到目標元素周圍,且能自動翻轉到適合位置,避免使用Javascript。 它的兼容性: chrome125+, safari26+, ff 不支持。
下面例子演示了:CSS錨點定位。tooltip會錨定在button的上下, 當滾動到邊界時,會自動翻轉顯示。
.my-button {
anchor-name: --my-btn-anchor; /* 定義一個名為 --my-btn-anchor 的錨點 */
}
.my-tooltip {
position: absolute; /* 或 fixed */
position-anchor: --my-btn-anchor; /* 關聯到上面定義的錨點 */
position-area: bottom;
position-try-fallbacks: flip-block;
}
思考一個問題:如果my-tooltip元素有小三角指示方向,那麼簡單的翻轉後,小三角的位置怎麼旋轉呢?
答案是:定位元素無法意識(be aware)狀態,小三角方向會錯誤。
此問題的解決方案即本次新增了CSS錨定容器查詢能力,它通過指定tooltip的 container-type: anchored, 然後使用@container anchored 的查詢語法,就讓tooltip查詢到,意識到自身的翻轉狀態(fallbacks 狀態)。
.tooltip {
container-type: anchored;
/* 默認在下方, 小三角向上,位置在底部 */
&::before {
content: '▲';
position: absolute;
bottom: 100%;
}
}
/** 當容器查詢到錨點變化 */
@container anchored(fallback: flip-block) {
.tooltip::before {
/* 小三角向下,並移到到頂部 */
content: '▼';
bottom: auto;
top: 100%;
}
}
要講明白錨點定位需要很大篇幅,且該示例複雜,大家可以轉到官網查看示例。 目前 container-type: anchored 的文檔連MDN上都沒有,是比較新的概念。
container-type有效值:
- normal: 元素不支持任何查詢
- size: 支持 inline 和 block 元素的尺寸的高度和寬度查詢
- inline-size: 僅支持 inline 元素的尺寸的寬度查詢
- scroll-state: 支持滾動態的偏移量和是否滾動到底等查詢,chrome 133+, 但ff,safari均不支持
- anchored: 錨點查詢
兼容性:
container-type: anchored 支持 chrome 143+ ,但ff,safari均不支持😭,且css 特性無法Polyfill。
總結
通過以上種種新特性,可以看出chrome 不僅關注使用用户體驗,更關注開發者體驗。通過增加類似command屬性,或者Light Dismiss的默認行為,以及滾動容器,滾動容器偽元素等技巧,讓許多場景都可以無Javascript實現了。 不僅大大減少開發代碼,還有極強的DOM可讀性。
我目前從事於組件庫開發。在組件庫的開發時,所採用的技術通常是落後於瀏覽器最新技術的,理由就是為了兼容用户瀏覽器。比如 dialog 元素已經是廣泛兼容,但目前仍沒有見到哪個組件庫使用它。通過這次梳理技術,感覺藉助 dialog 以及 popover api 可以極大簡化以往的組件開發,諸如:監聽按鍵,計算z-index,計算彈出層位置,監聽滾動進行位置跟隨等等,這些是問題bug集中爆發區,現在基本都可以無Js代碼的實現了。
另外,前面的諸多未廣泛兼容的技術,大都有相應的Polyfill,尤其是屬性,函數和事件的Polyfill基本都能找到。CSS的新偽類,偽元素雖然很難有Polyfill,但可以用添加類名的方案來兼容,輔助以一些Js事件就可以實現某種程度上的polyfill。oddbird.tech是一家服務公司,得到過Google的贊助,它們一直關注開發Popover API和 Anchor positioning的兼容方案。這些方案都讓我們以及早的使用新技術進行開發。
如果只需要支持最新的瀏覽器,前端的春天來了!
關於OpenTiny
歡迎加入 OpenTiny 開源社區。添加微信小助手:opentiny-official 一起參與交流前端技術~
OpenTiny 官網:https://opentiny.design
OpenTiny 代碼倉庫:https://github.com/opentiny
TinyVue 源碼:https://github.com/opentiny/tiny-vue
TinyEngine 源碼: https://github.com/opentiny/tiny-engine
歡迎進入代碼倉庫 Star🌟TinyEngine、TinyVue、TinyNG、TinyCLI、TinyEditor~
如果你也想要共建,可以進入代碼倉庫,找到 good first issue 標籤,一起參與開源貢獻~