博文精读:Chrome CSS 2025年回顾

本文由体验技术团队申君健原创。

序言

近日发现 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 方案

总结

  1. 该特性的核心价值不仅在于减少 JavaScript 代码量,更在于实现了更好的可读性,更好的语义化,更好的AI识别。Dialog元素是存在较久的冷门标签,Popover API是近两年的新特性,之前操作他们必须通过Javascript代码。
  2. 该特性也是一个微型的通知系统,某些程度上可以代替 new CustomEvent的使用。同样的,更好的可读性,参见图片翻转的示例。
  3. 命令源只能是Button,某种程度上限制了它的使用。

二、对话框轻量关闭(Dialog Light Dismiss)

一句话的解释

继 Popover Api 引入 Light Dismiss 之后,Dialog 也支持了它 完整示例

Light Dismiss 直接翻译就是轻量关闭,友好关闭,具体是指通过点击 ::backdrop 区域、按下 Esc 键即可触发目标元素自动关闭的交互行为。Light Dismiss同样的具备声明式可阅读性,还能避免Javascript的使用。

html 复制代码
<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

html 复制代码
<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组件场景。

html 复制代码
  <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节的内容有一些重要的差异:

  1. 强调必须非点击事件,场景对应"悬而未决"的状态,可以配合popover="hint"使用。
  2. 触发源更广泛,不仅是Button元素,还允许 <a>, <button>,<area>,SVG <a>
  3. hint类别不影响auto类别的弹窗,不会主动触发auto弹窗关闭。

长期以来Web标准对hover行为是淡视的,只有title属性和 :hover的伪类,一直缺少关键的hover事件。此次提供 interest事件,借此可以变相的视为一种hover事件

兼容性

支持chrome 142+, 不支持:ff,safari, polyfill 方案

四、可自定义的select (Customizable select)

一句话的解释

增强的select 和 option 元素,丰富的伪类、伪元素,定制更容易 完整示例

可定制的select增加了很多dom规范和伪类,伪元素,内容太多不宜展开细述,感兴趣看上面的完整MDN示例,我已经增加详细的注释。此处仅列出一些重要的概念和事项,以便能快速理解:

  1. base-select 设置:

select 和 ::picker(select)伪元素都必须添加规则: appearance: base-select ,以区别于传统select样式。

  1. 弹出层::picker(select)特性:

它渲染在页面顶层Top Layer,这意味着它会显示在所有其他内容之上,不会被父容器裁剪。浏览器还会根据视口中的可用空间自动调整下拉列表的位置和翻转。

  1. 增强的option:

传统的option元素仅支持 label,value属性和selected,disabled的布尔属性。option中嵌套有其它元素,都是会忽略的

增强后的option元素支持嵌套span,img等等普通元素,但要避免嵌套 a, input 等交互元素就行了。

  1. 新增 selectedcontent 元素:

该元素必须遵循 select > button > selectedcontent 的嵌套结构,详见示例。

select的选择值(即change事件)之后,选中的option的节点会被cloneNode创建副本,插入到selectedcontent中,所以他们结构一样,但不是同一个元素实例。

同时button是惰性的,不响应focus等,行为更像是 div

option 和 selectedcontent 的子项,都可以用普通的 css 选择器去分别控制样式。

  1. select 借用 Popover API

隐式借用了非常多的Popover 特性,比如 :popover-open伪类,无需anchor-name的隐式的锚点引用,且可以定义弹出层与锚点的位置关系,溢出翻转等等。

  1. select的multiple 和 optgroup 未增强

这意味着多选和分组功能,需要重新实现,对于组件库的作者来说,这无疑得回退到传统方案,幸好有Popover API。

兼容性:

支持 chrome 135+ , ff,safari均 不支持😭,polyfill 方案

这个方案并非真正意义的polyfill, 它使用自定义的 webComponent技术实现了平替。

五、滚动控制伪元素(::scroll-marker/button())

一句话的解释

为滚动容器的添加伪元素,用于控制容器滚动 完整示例

HTML早早添加了dialog, detail 等元素,但一直没有增加一个轮播图元素,今年只抠抠搜搜添加了三个伪元素,或许是因为添加一个新元素需要考虑的事情太多。

  1. ::scroll-button() 滚动容器按钮的伪元素,点击它会触发容器滚动。它非常类似于 ::before, ::after作用, 都需要content才显示,且呈现在容器的内部。

每个容器最多有4个滚动方向,括号的作用是指定滚动方向,可取值:*, left,right,up,down, block-end,block-start, inline-end,inline-start等。

按钮伪元素具有状态,比如容器滚动到两端之后,滚动按钮会自动禁用。 它具有以下状态: enabled, disabled,hover,active,focus

  1. ::scroll-marker 是滚动容器中,指示滚动项的伪元素,它同样也需要content才显示。

它具有 :target-current 伪类, 表示滚动到当前滚动项。当然, :hover, :active等伪类也能使用

  1. ::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的上下, 当滚动到边界时,会自动翻转显示。

css 复制代码
.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 状态)。

css 复制代码
.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 APIAnchor 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 标签,一起参与开源贡献~

相关推荐
一只大侠的侠5 小时前
Flutter开源鸿蒙跨平台训练营 Day 10特惠推荐数据的获取与渲染
flutter·开源·harmonyos
崔庆才丨静觅7 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60617 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了7 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅7 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅8 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
猫头虎8 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven
崔庆才丨静觅8 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment8 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅9 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端