发布时间:2025 年 8 月 14 日
随着 Google I/O 大会季接近尾声,本文将回顾今年在我们的活动中分享的 CSS 和 Web 界面方面的精彩亮点。
开发者曾经梦寐以求的强大功能已在浏览器中实现,并且比以往更快地实现了跨浏览器兼容性。不过,尽管取得了这些进展,但一些最常见的界面模式仍然很难正确实现。您通常必须依赖 JavaScript 框架、复杂的 CSS 技巧和大量的自定义代码来构建本应更简单的组件。
Chrome 团队正与 CSSWG 和 WHATWG 等其他浏览器供应商、标准机构以及 Open UI 等社区群组合作,致力于让这些基本界面模式真正易于实现。
可自定义的选择菜单
<select>
元素对于表单至关重要,但其内部结构历来受到浏览器的屏蔽,因此几乎无法实现一致且全面的 CSS 样式设置。若要构建更好的 <select>
,需要了解其构建块,即 Popover API 和 CSS Anchor Positioning API。
Popover API:现已纳入 Baseline
自定义下拉菜单需要一个浮动选项框,该框显示在所有其他界面元素之上,可以轻松关闭,并且可以正确管理焦点。弹出式窗口 API 可处理所有这些问题,并且截至今年,该 API 已达到“Baseline Newly available”状态,这意味着它在所有主要浏览器中都处于稳定状态。
创建弹出式窗口需要两个部分:触发元素(例如 <button>
)和弹出式窗口元素本身。通过为弹出式窗口提供 id
和 [popover]
属性来连接它们,然后在按钮的 [popovertarget]
属性中引用该 id
。
Popover API 可管理元素的整个生命周期,并提供以下功能:
- 顶层渲染:无需再与 z-index 作斗争。
- 可选的轻关闭功能:当用户点击弹出式窗口区域之外的位置时,系统会关闭弹出式窗口。
- 自动焦点管理:浏览器处理标签页在弹出式窗口中的导航。
- 无障碍绑定:底层互动模型由原生处理。
<dialog>
元素升级
虽然弹出式窗口功能强大,但并不总是正确的选择。例如,在需要用户反馈的页面阻塞互动中,模态 <dialog>
更为合适。
过去,<dialog>
缺少 [popover]
的一些便利功能,但这种情况正在发生变化。借助新的 closedby="any"
属性,模态对话框现在支持轻触关闭功能,即在用户点击外部或按 Escape 键时关闭。
此外,命令调用方([command]
和 [commandfor]
)提供了一种声明式、无需 JavaScript 的方式来将按钮连接到操作,例如使用 command="show-modal"
打开对话框。
<dialog> 元素 + closedby=any + 命令调用程序 |
[popover] 个属性 |
|
---|---|---|
主要用途 | 模态互动(用户协议、导览等) | 临时界面(菜单、提示、卡片、Toast 提醒) |
可轻度关闭 | 是 | 是 |
捕获焦点 | 是 | 否 |
“惰性”页面 | 是 | 否 |
声明式激活 | 是 | 是 |
实现 | 元素 | 属性 |
在顶层渲染 | 是 | 是 |
完全可设置样式 | 是 | 是 |
CSS 锚点定位
弹出式窗口显示后,需要相对于打开它的元素进行定位。使用 JavaScript 手动计算此值既不稳定,又会降低性能。
从 Chrome 125 开始,您可以使用 CSS Anchor Positioning API。这项新功能可以声明式地将一个元素与另一个元素关联起来,并在前者靠近屏幕边缘时自动处理其重新定位。此功能是 Interop 2025 的一部分,这是一项跨浏览器计划,旨在实现备受期待的功能,这意味着我们有望在 2025 年底之前在所有主流浏览器中使用此功能。

虽然您可以使用 anchor-name
和 position-anchor
属性显式关联元素,但规范和 Chrome 133 中的更新会在 <popover>
及其调用方 <button>
之间创建隐式锚点关系。这大大简化了代码,意味着您现在可以使用一行 CSS(例如 position-area: bottom span-left
)来定位弹出式窗口。
chrome.dev 中的锚定工具展示了如何使用 position-area
来获取您可能需要的放置位置:
更进一步,通过使用 position-try-fallbacks
定义回退,让浏览器重新定位锚点,防止锚点超出屏幕范围。以下演示展示了一个使用此属性进行内置重新定位逻辑的 popover:
真正可自定义的 <select>
在之前的版本中,这些构建块已就位,现在 Chrome 134 中终于实现了 <select>
元素的 Web 原生样式。这包括新的 appearance
属性、新的伪元素和 <selectedcontent>
元素。
如需解锁自定义功能,请将 appearance: base-select;
应用于 <select>
元素及其新的 ::picker(select)
伪元素,该伪元素以选项下拉列表为目标。这会公开新的内部样式设置部分,包括:
<selectedcontent>
:表示按钮中显示的所选选项的内容。::picker-icon
:下拉箭头图标<option>:checked
和::checkmark
:用于设置所选选项及其对勾标记指示器的样式

这样,您就可以在选项中添加丰富的内容,并对显示进行精细控制。例如,您可以在选项列表中显示图标和字幕,但使用 selectedcontent
中的 display: none
在关闭状态下隐藏它们。
最棒的是,此 API 可以逐步增强。在不支持这些功能的浏览器中,用户仍会获得一个可正常运行的 Web 原生选择器。您可以在保留 Web 原生选择元素的内置无障碍功能、键盘导航和表单集成功能的同时,获得自定义外观。
轮播广告
轮播界面在网络上随处可见,而不仅仅是在首页部分。这包括紧凑型布局(例如应用商店界面)中的可水平滚动的内容。但在 Web 上构建轮播界面仍然很困难,需要考虑许多因素,例如状态管理、滚动卡顿、互动性和无障碍功能。但仔细想想,轮播界面本质上是具有额外界面可供性的精美滚动区域。
滚动器使用入门
如需构建轮播界面,首先需要创建一个包含溢出容器的项的列表。如需隐藏水平滚动条,同时保持内容可滚动,请使用 scrollbar-width: none
。此外,为了使滚动条感觉“快速”,请应用 scroll-snap-type
和 scroll-snap-align
,确保项目在用户滚动时贴靠到位。
使用 ::scroll-button
进行上一个和下一个操作
Chrome 135 中新增的 ::scroll-button()
伪元素可指示浏览器生成有状态且无障碍的“下一项”和“上一项”按钮。浏览器会自动处理正确的 ARIA 角色和 Tab 键顺序,甚至在到达开头或结尾时停用按钮,而无需添加任何 JavaScript。
如需启动滚动按钮,请为其提供内容和无障碍标签,如下所示:
.carousel {
&::scroll-button(left) {
content: "⬅" / "Scroll Previous";
}
&::scroll-button(right) {
content: "⮕" / "Scroll Next";
}
}

使用 CSS 锚点定位功能设置这些按钮的样式,并将其定位到相对于其父轮播界面的位置,这是推荐的做法。
使用 ::scroll-marker
进行直接导航
对于圆点指示器或缩略图,::scroll-marker
和 ::scroll-marker-group
伪元素可将导航标记直接与滚动容器中的项相关联。浏览器会将该组视为 tablist
并处理键盘导航。
与滚动按钮类似,您可以通过选择 content
属性来启动滚动标记,并提供无障碍标签。在以下示例中,使用数据属性来设置滚动标记的标签。此外,使用 scroll-marker-group
属性将滚动标记定位在 ::scroll-marker-group
中。最后,使用新的 :target-current
伪类设置有效标记的样式。下面是一个基本轮播界面的示例:
.carousel {
scroll-marker-group: after;
> li::scroll-marker {
content: ''/ attr(data-name);
}
> li::scroll-marker:target-current {
background: blue;
}
}

滚动状态查询
借助与滚动相关的新 CSS 功能,您可以创建更灵活、互动性更强的轮播界面。滚动状态查询是一种新的媒体查询,可根据滚动器的状态应用。共有三种不同类型的滚动状态查询,可在 @container
语句中使用 scroll-state()
进行访问。它们分别是:
scroll-state(snapped)
:当元素处于“贴靠”位置时匹配。在轮播界面中,当某项内容位于轮播界面的中心时,即为“已贴靠”。scroll-state(stuck)
:当父元素变为粘性时,设置元素的样式,例如标题。scroll-state(scrollable)
:添加淡出等视觉指示器,以表明还有更多内容可供滚动。
综合应用
借助新的 CSS 轮播界面基元、滚动状态查询和锚点定位功能,您可以更轻松地构建自定义的互动式轮播界面。您还可以进一步采用滚动驱动的动画,将动画直接与滚动位置相关联,从而创建高性能效果,例如让项目在滚动到视图中时进行缩放和淡入。这些动画在主线程之外运行,可实现丝滑流畅的体验。
此互动式轮播界面结合了 scroll-state()
查询、::scroll-button
、::scroll-marker
、CSS 锚点定位和 :target-current
。
此外,您还可以使用名为 interactivity
的新属性来帮助用户专注于当前内容。interactivity: inert
允许用户使用 CSS 应用惰性,使屏幕外的轮播界面元素无法聚焦,并将其从无障碍树中移除。
详细了解 CSS 轮播界面。
互动式悬停卡片
悬停卡片(当您将鼠标悬停在用户名或链接上时显示的丰富弹出式窗口)非常有用,但众所周知,很难正确构建。要正确处理延迟、事件处理和多设备支持,可能需要一个专门的团队花费数月时间。不过,我们正在开发一种新的声明式解决方案,该方案应能彻底解决此问题。
通过 [interestfor]
实现的基于兴趣的悬浮框
声明式悬停卡背后的核心魔法是 [interestfor]
属性。这项即将推出的功能可提供弹出式窗口的强大功能,但会根据用户的“兴趣”触发这些窗口。例如,在指针设备上,用户感兴趣的操作包括指针悬停、使用键盘进行标签页导航,以及在触摸屏上进行长按或点按。移动互动问题尚未解决。
如需将基于点击的弹出式窗口转换为基于兴趣的弹出式窗口,请构建一个调用元素(可以是 <button>
或 <a>
),并为其提供一个 [interestfor]
属性,该属性的值等于 [popover]
元素的 id
。在 HTML 中,此代码如下所示:
<button interestfor="profile-callout">
...
</button>
<div id="profile-callout" popover>
...
</div>
浏览器会处理所有复杂的事件逻辑,包括:
- 进入和退出事件:在精细指针设备上悬停进入,使用键盘进行 Tab 键导航,在粗略指针设备上长按或触摸。
- 事件延迟:使用单个 CSS 属性控制进入和退出延迟。
此功能支持其他弹出式窗口功能,例如顶层支持,其中弹出式窗口在 DOM 树其余部分之上的新层中呈现。语义组件绑定和底层无障碍树模型由原生处理。
样式兴趣调用者
兴趣调用器包含一些新功能。其中一项功能是能够使用 CSS 属性 interest-target-delay
控制进入和退出延迟。另一个是能够使用 :has-interest
伪类根据调用元素是否具有兴趣来设置其样式。
[interesttarget] {
interest-target-delay: 0s 1s;
&:has-interest {
background: yellow;
}
}
popover="hint"
和多功能界面
对于旨在激发兴趣的元素,一个关键的难题是新的浮层类型:popover="hint"
。与其他弹出式窗口的主要区别在于,提示弹出式窗口在打开时不会关闭其他弹出式窗口。这非常适合用于应在不关闭已打开的菜单或聊天窗口的情况下显示的提示或预览卡片。
Browser Support
popover=auto | popover=manual | popover=hint | |
---|---|---|---|
轻度关闭(通过点击外部区域或 esc 键) | 是 | 否 | 是 |
打开时关闭其他 popover=auto 元素 | 是 | 否 | 否 |
打开时关闭其他 popover=hint 元素 | 是 | 否 | 是 |
打开时关闭其他 popover=manual 元素 | 否 | 否 | 否 |
可以使用 JS(showPopover() 或 hidePopover() )打开和关闭弹出式窗口 | 是 | 是 | 是 |
下一个标签页停止位置的默认焦点管理 | 是 | 是 | 是 |
可隐藏或通过 popovertargetaction 切换 | 是 | 是 | 是 |
可在父级 popover 中打开,以保持父级打开状态 | 是 | 是 | 是 |
这使您能够以声明方式构建功能强大的多功能界面。现在,单个按钮可以使用 popovertarget
作为其主要点击操作(例如打开通知面板),并使用兴趣调用提示弹出式窗口在指针悬停时显示实用提示。
未来是声明式的
本文介绍的功能标志着我们正朝着更强大、更声明式的 Web 平台迈出根本性的一步。通过让浏览器处理复杂且重复的状态管理和无障碍功能工作,我们可以移除大量 JavaScript 代码,提升性能,并专注于我们最擅长的事情:打造创新且富有吸引力的用户体验。这确实是 Web 界面的黄金时代,而这仅仅是开始。请在此处关注我们的动态,了解我们如何打造更强大、更易用的 Web。
其他资源: