Web 平台正蓬勃发展,不断创新,而 CSS 和 Web 界面功能正处于这一激动人心的发展历程的最前沿。我们正处于 Web 界面设计的黄金时代,新的 CSS 功能正以我们前所未有的速度在各个浏览器中推出,为打造精美且富有吸引力的 Web 体验开辟了无限可能。 这篇博文将深入探讨 CSS 的当前状态,重点介绍在 2024 年 Google I/O 大会上实时展示的一些最具颠覆性的新功能,这些功能正在重新定义我们构建 Web 应用的方式。
新颖的互动体验
从根本上讲,网站体验是您与用户之间的调用和响应,因此,投资于高质量的用户互动非常重要。我们一直在努力进行一些重大改进,以解锁之前从未在网页上实现过的功能,从而让用户能够在网页中和在网页之间进行导航。
滚动驱动的动画
顾名思义,滚动条驱动的动画 API 可让您创建动态的基于滚动的动画,而无需依赖滚动条观察器或其他繁重的脚本。
创建滚动条驱动的动画
与平台上的基于时间的动画类似,您现在可以使用滚动器的滚动进度来启动、暂停和反向播放动画。因此,当您向前滚动时,会看到动画进度;当您向后滚动时,动画进度会反向变化。这样一来,您就可以创建部分或全页视觉效果,让元素在视口中呈现动画效果,从而打造动态视觉冲击力,这种效果也称为滚动叙事。
滚动驱动的动画可用于突出显示重要内容、引导用户浏览故事,或只是为网页增添动态效果。
滚动驱动的动画视觉效果
实时演示
@keyframes appear {
from {
opacity: 0;
scale: 0.8;
}
to {
opacity: 1;
scale: 1;
}
}
img {
animation: appear linear;
animation-timeline: view();
animation-range: entry 25% cover 50%;
}
上述代码定义了一个简单的动画,该动画通过更改图片的不透明度和缩放比例显示在视口中。动画由滚动位置驱动。如需创建此效果,请先设置 CSS 动画,然后设置 animation-timeline。在这种情况下,采用默认值的 view() 函数会跟踪相对于滚动视口的图片(在本例中,滚动视口也是视口)。
请务必考虑浏览器支持和用户偏好,尤其是无障碍功能需求。因此,请使用 @supports 规则检查浏览器是否支持滚动驱动的动画,并将滚动驱动的动画封装在用户偏好设置查询(例如 @media (prefers-reduced-motion: no-preference))中,以尊重用户的动画偏好设置。完成这些检查后,您便可以确定样式能够正常运行,并且动画不会给用户带来问题。
@supports (animation-timeline: view()) {
@media (prefers-reduced-motion: no-preference) {
/* Apply scroll-driven animations here */
}
}
滚动驱动的动画可以是全页滚动叙事体验,也可以是更细致的动画,例如在您滚动 Web 应用时,标题栏最小化并显示阴影。
滚动驱动的动画视觉效果
实时演示
@keyframes shrink-name {
from {
font-size: 2em;
}
to {
font-size: 1.5em;
}
}
@keyframes add-shadow {
from {
box-shadow: none;
}
to {
box-shadow: 0 4px 2px -2px gray;
}
}
header {
animation: add-shadow linear both;
}
h2 {
animation: shrink-name linear both;
}
header, h2 {
animation-timeline: scroll();
animation-range: 0 150px;
}
此演示使用了几个不同的关键帧动画(标题、文字、导航栏和背景),然后将相应的滚动驱动动画应用于每个关键帧动画。虽然它们的动画样式各不相同,但都具有相同的动画时间轴、最近的滚动条和相同的动画范围(从网页顶部到 150 像素)。
滚动条驱动的动画带来的性能优势
此内置 API 可减少您需要维护的代码负担,无论是您编写的自定义脚本还是包含的其他第三方依赖项。它还消除了对各种滚动观察器的需求,这意味着性能方面会有相当大的提升。这是因为,无论您是直接在 CSS 中使用新 API 还是使用 JavaScript 钩子,当动画属性(如转换和不透明度)可在合成器上实现动画效果时,滚动驱动的动画都会在主线程之外运行。
Tokopedia 最近使用了滚动驱动的动画,以便在您滚动时显示商品导航栏。使用此 API 在代码管理和性能方面都带来了显著优势。
“与使用常规 JS 滚动事件相比,我们成功减少了多达 80% 的代码行,并观察到滚动时的平均 CPU 使用率从 50% 降至 2%。- Andy Wihalim,Tokopedia 高级软件工程师”
滚动效果的未来
我们知道,这些效果将继续让网络变得更具吸引力,并且我们已经在考虑接下来可能会出现哪些新功能。这包括不仅可以使用新的动画时间轴,还可以使用滚动点来触发动画的开始,即滚动触发的动画。
未来,浏览器还将推出更多滚动功能。以下演示展示了这些未来功能的组合。它使用 CSS scroll-start-target 在选择器中设置初始日期和时间,并使用 JavaScript scrollsnapchange 事件更新标题日期,从而轻松实现数据与捕捉到的事件的同步。
您还可以基于此代码,使用 JavaScript scrollsnapchanging 事件实时更新选择器。
这些特定功能目前仅在 Canary 版中通过标志启用,但它们解锁了以前在平台中无法实现或很难实现的功能,并突显了未来基于滚动的互动可能性。
如需详细了解如何开始使用滚动驱动的动画,我们的团队刚刚发布了一个新的视频系列,您可以在 Chrome for Developers YouTube 频道上找到该系列视频。在此处,您将学习 Bramus Van Damme 介绍的滚动驱动动画基础知识,包括该功能的工作原理、词汇、创建效果的各种方式,以及如何组合效果来打造丰富的体验。这是一部非常值得观看的视频系列。
查看过渡
我们刚刚介绍了一项强大的新功能,用于在网页内添加动画效果,但还有一项强大的新功能,称为“视图过渡”,用于在网页浏览之间添加动画效果,以打造顺畅的用户体验。视图过渡为网页带来了全新的流畅度,让您可以在单个网页内甚至不同网页之间创建无缝过渡。
Airbnb 是已经开始尝试将视图过渡效果集成到其界面中的公司之一,旨在提供流畅无缝的网页浏览体验。这包括列出编辑器边栏,到编辑照片和添加设施,所有这些都在一个流畅的用户体验流程中进行。
虽然这些全屏效果美观且流畅,但您也可以创建微互动,例如此示例中在用户互动时更新列表视图。使用视图转换功能,您可以轻松实现此效果。
在单页应用中快速启用视图过渡的方法非常简单,只需使用 document.startViewTransition 封装互动,并确保每个过渡元素都具有 view-transition-name(内嵌)或使用 JavaScript 在创建 DOM 节点时动态添加。
演示视觉效果
实时演示
document.querySelectorAll('.delete-btn').forEach(btn => {
btn.addEventListener('click', () => {
document.startViewTransition(() => {
btn.closest('.card').remove();
});
})
});
/* Styles for the transition animation */
::view-transition-old(.card):only-child {
animation: fade-out ease-out 0.5s;
}
查看过渡类
视图转换名称可用于为视图转换应用自定义动画,但如果有很多元素需要转换,这种做法可能会很麻烦。今年,我们首次更新了视图过渡功能,简化了此问题,并引入了创建可应用于自定义动画的视图过渡类的功能。
查看过渡类型
视图转换的另一项重大改进是支持视图转换类型。当您希望在动画显示网页视图时采用不同的视觉视图过渡类型时,视图过渡类型会非常有用。
例如,您可能希望首页以不同于博客页面返回首页的方式动画显示到博客页面。或者,您可能希望页面以不同的方式交换进出,例如在本例中,从左到右,反之亦然。以前,这样做很麻烦。您需要将类添加到 DOM 以应用样式,然后必须移除这些类。借助视图过渡类型,浏览器可以清理旧过渡,而无需您在启动新过渡之前手动执行此操作,从而为您完成这项工作。
您可以在 document.startViewTransition 函数中设置类型,该函数现在接受对象。update 是用于更新 DOM 的回调函数,types 是包含类型的数组。
document.startViewTransition({
update: myUpdate,
types: ['slide', 'forwards']
})
多页面视图过渡
Web 的强大之处在于其广阔性。许多应用不仅是单页应用,还是包含多个页面的强大组合。因此,我们非常激动地宣布,我们将在 Chromium 126 中为多页应用提供跨文档视图过渡支持。
这一新的跨文档功能集包括在同源内运行的 Web 体验,例如从 web.dev 导航到 web.dev/blog,但不包括跨源导航,例如从 web.dev 导航到 blog.web.dev 或其他网域(如 google.com)。
与同文档视图过渡相比,一个主要区别在于您无需使用 document.startViewTransition() 封装过渡。请改为使用 CSS @view-transition at-rule,选择启用视图过渡中涉及的两个页面。
@view-transition {
navigation: auto;
}
如需实现更自定义的效果,您可以使用新的 pageswap 或 pagereveal 事件监听器挂钩 JavaScript,从而访问视图过渡对象。
借助 pageswap,您可以在拍摄旧快照之前对即将离开的网页进行一些临时更改;借助 pagereveal,您可以在新网页初始化后开始渲染之前对其进行自定义。
window.addEventListener('pageswap', async (e) => {
// ...
});
window.addEventListener('pagereveal', async (e) => {
// ...
});
未来,我们计划扩展视图过渡功能,包括:
- 范围限定的过渡效果:可让您将过渡效果限制在 DOM 子树中,从而使网页的其余部分保持互动性,并支持同时运行多个视图过渡效果。
- 手势驱动的视图过渡:使用拖动或滑动手势触发跨文档视图过渡,以在网页上获得更接近原生应用的体验。
- CSS 中的导航匹配:直接在 CSS 中自定义跨文档视图过渡,而无需在 JavaScript 中使用
pageswap和pagereveal事件 如需详细了解多页应用的视图过渡,包括如何通过预渲染以最佳性能设置视图过渡,请观看 Bramus Van Damme 的以下讲座:
引擎驱动的界面组件:简化复杂的互动
构建复杂的 Web 应用并非易事,但 CSS 和 HTML 正在不断发展,以使这一过程更易于管理。新功能和增强功能简化了界面组件的创建,让您可以专注于打造出色的体验。这是通过多方协作完成的,涉及多个关键标准机构和社区群组,包括 CSS 工作组、Open UI 社区群组和 WHATWG(Web 超文本应用技术工作组)。
对于开发者来说,一个很大的痛点是看似简单的需求:能够设置下拉菜单(选择元素)的样式。虽然表面上看起来很简单,但这是一个复杂的问题,涉及平台的许多方面:从布局和渲染,到滚动和互动,再到用户代理样式和 CSS 属性,甚至包括 HTML 本身的变化。
下拉菜单由许多部分组成,包含许多必须考虑的状态,例如:
- 键盘绑定(用于进入/退出互动)
- 点击即可关闭
- 有效的弹出式窗口管理(当一个弹出式窗口打开时,关闭其他弹出式窗口)
- 标签页焦点管理
- 直观呈现所选选项值
- 箭头互动样式
- 状态管理(打开/关闭)
目前,自行管理所有这些状态非常困难,但平台也并未提供便利。为了解决这个问题,我们分解了这些部分,并推出了一些基本功能,这些功能不仅可以设置下拉菜单的样式,还可以实现更多功能。
Popover API
首先,我们发布了一个名为 popover 的全局属性,我很激动地宣布,该属性在几周前刚刚达到“基准”状态。
Popover 元素会通过 display: none 隐藏,直到通过调用方(例如按钮)或 JavaScript 打开。如需创建基本的弹出式窗口,请在元素上设置 popover 属性,并使用 popovertarget 将其 ID 关联到按钮。现在,按钮是调用方,
演示视觉效果
实时演示
<button popovertarget="my-popover">Open Popover</button>
<div id="my-popover" popover>
<p>I am a popover with more information.</p>
</div>
启用 popover 属性后,浏览器无需任何额外的脚本即可处理许多关键行为,包括:
- 提升到顶层。:位于网页其余部分之上的单独层,因此您无需使用
z-index。 - 轻触即关闭功能。:点击弹出框区域以外的位置会关闭弹出框并返回焦点。
- 默认标签页焦点管理。:打开弹出式窗口后,下一个标签页会停留在弹出式窗口内。
- 内置键盘绑定。:按
esc键或双重切换会关闭弹出式信息框并返回焦点。 - 默认组件绑定。:浏览器在语义上将弹出式窗口与其触发器相关联。
您甚至可能在不知不觉中已经在使用此弹出式窗口 API。GitHub 在其首页的“新建”菜单和拉取请求审核概览中实现了弹出式窗口。他们使用由 Oddbird 构建并获得 GitHub 自己的 Keith Cirkel 大力支持的 popover polyfill 逐步增强了此功能,以支持旧版浏览器。
“通过迁移到 Popover,我们成功弃用了数千行代码。Popover 通过以下方式帮助我们:无需再与神奇的 z-index 数字作斗争;通过声明式按钮行为建立正确的无障碍树关系;内置焦点行为,使我们的设计系统能够以正确的方式实现模式,从而大大简化了相关工作。-Keith Cirkel,软件工程师,GitHub”
为进入和退出效果添加动画
如果您有弹出式界面,可能需要添加一些互动。过去一年中,我们推出了 4 项新的互动功能,以支持动画弹出式窗口。其中包括:
能够在关键帧时间轴上为 display 和 content-visibility 添加动画效果。
使用 transition-behavior 属性和 allow-discrete 关键字可启用离散属性(如 display)的过渡效果。
用于将入口效果从 display: none 动画化到顶层的 @starting-style 规则。
用于控制动画期间顶层行为的叠加层属性。
这些属性适用于您要添加动画效果并移至顶层的任何元素,无论是弹出式窗口还是对话框。对于带有背景的对话框,整体效果如下所示:
演示视觉效果
实时演示
dialog, ::backdrop{
opacity: 0;
transition: opacity 1s, display 1s allow-discrete, overlay 1s allow-discrete;
}
[open], [open]::backdrop {
opacity: 1;
}
@starting-style {
[open], [open]::backdrop {
opacity: 0;
}
}
首先,设置 @starting-style,以便浏览器知道要将此元素从哪些样式动画化到 DOM 中。对话框和背景幕布均会执行此操作。然后,为对话框和背景设置打开状态的样式。对于对话框,此属性使用 open 属性;对于弹出式窗口,此属性使用 ::popover-open 伪元素。最后,使用 allow-discrete 关键字为 opacity、display 和 overlay 添加动画效果,以启用动画模式,在该模式下,离散属性可以进行过渡。
锚点定位
弹出式窗口只是故事的开始。一项非常令人兴奋的更新是,从 Chrome 125 开始,我们现在支持锚定位。
借助锚定定位,只需几行代码,浏览器即可处理将定位元素绑定到一个或多个锚定元素的逻辑。在以下示例中,每个按钮都锚定了一个简单的提示,该提示位于底部中心位置。
演示视觉效果
实时演示
在 CSS 中设置定位锚定关系,方法是在锚定元素(在本例中为按钮)上使用 anchor-name 属性,并在定位元素(在本例中为提示)上使用 position-anchor 属性。然后,使用 anchor() 函数相对于锚点应用绝对或固定定位。以下代码将提示的顶部定位到按钮的底部。
.anchor {
anchor-name: --my-anchor;
}
.positioned {
position: absolute;
position-anchor: --my-anchor;
}
或者,您也可以直接在锚点函数中使用锚点名称,并跳过 position-anchor 属性。当锚定到多个元素时,此功能非常有用。
.anchor {
anchor-name: --my-anchor;
}
.positioned {
position: absolute;
top: anchor(--my-anchor bottom);
}
最后,对 justify 和 align 属性使用新的 anchor-center 关键字,以将定位元素居中对齐到其锚点。
.anchor {
anchor-name: --my-anchor;
}
.positioned {
position: absolute;
top: anchor(--my-anchor bottom);
justify-self: anchor-center;
}
虽然将锚点定位与弹出式窗口搭配使用非常方便,但弹出式窗口绝对不是使用锚点定位的必要条件。锚点定位可与任意两个(或更多)元素搭配使用,以创建视觉关系。事实上,以下演示(灵感来自 Roman Komarov 的一篇文章)展示了当您将鼠标悬停在列表项上或使用 Tab 键选择列表项时,下划线样式如何锚定到列表项。
演示视觉效果
实时演示
此示例使用锚定函数,通过 left、right 和 bottom 的物理属性来设置锚定位置。当您将鼠标悬停在其中一个链接上时,目标锚点会发生变化,浏览器会移动目标以应用定位,同时还会为颜色添加动画效果,从而营造出整洁的效果。
ul::before {
content: "";
position: absolute;
left: anchor(var(--target) left);
right: anchor(var(--target) right);
bottom: anchor(var(--target) bottom);
...
}
li:nth-child(1) { --anchor: --item-1 }
ul:has(:nth-child(1) a:is(:hover, :focus-visible)) {
--target: --item-1;
--color: red;
}
inset-area 定位
除了您之前可能使用过的默认定向绝对定位之外,还包含一种新的布局机制,该机制已作为锚定位置 API 的一部分实现,称为“内边衬区”。通过插页区域,您可以轻松地相对于各自的锚定元素放置定位元素,并且可以在 9 单元格网格上使用,锚定元素位于中心。例如,inset-area: top 将定位元素放置在顶部,而 inset-area: bottom 将定位元素放置在底部。
第一个锚点演示的简化版本如下所示(使用 inset-area):
.anchor {
anchor-name: --my-anchor;
}
.positioned {
position: absolute;
position-anchor: --my-anchor;
inset-area: bottom;
}
您可以将这些位置值与 span 关键字结合使用,以从中心位置开始,向左跨越、向右跨越或跨越所有位置,从而占据所有可用的列或行。您也可以使用逻辑属性。为了更轻松地直观了解和掌握此布局机制,请在 Chrome 125 及更高版本中查看此工具:
由于这些元素是锚定元素,因此当锚定元素移动时,定位元素也会在网页上动态移动。在此示例中,我们有采用容器查询样式设置的卡片元素,这些元素会根据其固有尺寸调整大小(这是媒体查询无法实现的),并且锚定菜单会随着卡片界面发生变化而随新布局移动。
演示视觉效果
实时演示
使用 position-try-options 实现动态锚定位置
借助弹出式窗口和锚点定位的组合,可以更轻松地创建菜单和子菜单导航。此外,当锚定元素到达视口的边缘时,您还可以让浏览器为您处理位置变化。您可以通过以下几种方式实现此目的。第一种方法是创建自己的定位规则。在这种情况下,子菜单最初位于“店面”按钮的右侧。不过,您可以创建一个 @position-try 块,以在菜单右侧空间不足时使用,并为其指定自定义标识符 --bottom。然后,使用 position-try-options 将此 @position-try 块连接到锚点。
现在,浏览器会在这些锚定状态之间切换,先尝试右侧位置,然后移到底部。而且可以实现平滑的过渡。
演示视觉效果
实时演示
#submenu {
position-anchor: --submenu;
top: anchor(top);
left: anchor(right);
margin-left: var(--padding);
position-try-options: --bottom;
transition: top 0.25s, left 0.25s;
width: max-content;
}
@position-try --bottom {
top: anchor(left);
left: anchor(bottom);
margin-left: var(--padding);
}
除了显式定位逻辑之外,如果您想要实现一些基本互动(例如在块方向或内联方向上翻转锚点),浏览器还提供了一些关键字。
position-try-options: flip-block, flip-inline;
如需获得简单的翻转体验,请利用以下翻转关键字值,并完全跳过编写 position-try 定义。现在,您只需几行 CSS 代码,即可获得一个功能齐全的位置自适应锚定定位元素。
演示视觉效果
实时演示
.tooltip {
inset-area: top;
position-try-options: flip-block;
}
详细了解如何使用锚点定位。
分层界面的未来
我们随处可见关联体验,而本文中展示的这组功能是释放创意和更好地控制锚定位置元素及分层界面的绝佳开端。但这仅仅是开始。例如,目前 popover 仅适用于作为调用元素的按钮或 JavaScript。对于类似维基百科风格的预览(在整个 Web 平台上随处可见),需要能够与之互动,并且能够从链接和用户显示感兴趣的内容中触发弹出式窗口,而不必点击,例如悬停或标签页焦点。
作为弹出框 API 的下一步,我们正在开发 interesttarget,以满足这些需求,并更轻松地重新创建这些体验,同时内置适当的无障碍功能钩子。这是一个难以解决的无障碍性问题,围绕理想行为存在许多未解决的问题,但从平台层面解决并规范化此功能应能改善所有人的体验。
<a interesttarget="my-tooltip">Hover/Focus to show the tooltip</a>
<span popover=hint id="my-toolip">This is the tooltip</span>
此外,得益于两位第三方开发者 Keith Cirkel 和 Luke Warlow 的工作,我们还提供了一个面向未来的常规调用方 (invoketarget),供您在 Canary 版中进行测试。invoketarget 支持声明式开发者体验,popovertarget 提供弹出式窗口,针对所有互动元素(包括 <dialog>、<details>、<video>、<input type="file"> 等)进行标准化处理。
<button invoketarget="my-dialog">
Open Dialog
</button>
<dialog id="my-dialog">
Hello world!
</dialog>
我们知道,此 API 尚未涵盖某些用例。例如,设置将锚定元素与其锚点连接起来的箭头的样式,尤其是在锚定元素的位置发生变化时;以及使元素能够“滑动”并停留在视口中,而不是在到达其边界框时贴靠到设置的另一个位置。因此,虽然我们很高兴能推出这款强大的 API,但我们也期待在未来进一步扩展其功能。
可设置样式的 select
通过结合使用 popover 和 anchor,该团队在最终实现可自定义的选择下拉菜单方面取得了进展。好消息是,我们已经取得了很大进展。坏消息是,此 API 目前仍处于实验阶段。不过,我很高兴能分享一些实时演示和有关我们进展的最新动态,并希望获得您的一些反馈。首先,我们已在如何让用户选择加入新的可自定义精选体验方面取得进展。目前,正在开发中的一种方法是使用 CSS 中的外观属性,并将其设置为 appearance: base-select。设置外观后,您将选择启用新的可自定义的选择体验。
select {
appearance: base-select;
}
除了 appearance: base-select 之外,还有一些新的 HTML 更新。这些功能包括将选项封装在 datalist 中以进行自定义,以及在选项中添加任意非互动内容(例如图片)。您还可以访问一个新元素 <selectedoption>,该元素会将选项的内容反映到自身中,然后您可以根据自己的需求进行自定义。此元素非常实用。
演示视觉效果
实时演示
<select>
<button type=popover>
<selectedoption></selectedoption>
</button>
<datalist>
<option value="" hidden>
<p>Select a country</p>
</option>
<option value="andorra">
<img src="Flag_of_Andorra.svg" />
<p>Andorra</p>
</option>
<option value="bolivia">
<img src="Flag_of_Bolivia.svg" />
<p>Bolivia</p>
</option>
...
</datalist>
</select>
以下代码演示了如何在 Gmail 界面中自定义 <selectedoption>,其中使用直观的图标表示所选的回复类型,以节省空间。您可以在 selectedoption 中使用基本显示样式,以区分选项样式与预览样式。在这种情况下,选项中显示的文本可以在 selectedoption 中以视觉方式隐藏。
演示视觉效果
实时演示
selectedoption .text {
display: none;
}
为该 API 重用 <select> 元素的最大优势之一是向后兼容性。在此国家/地区选择界面中,您可以看到一个自定义界面,其中包含选项中的国旗图片,以便用户更轻松地解析内容。由于不受支持的浏览器会忽略它们不理解的行(例如自定义按钮、datalist、selectedoption 和选项中的图片),因此回退将类似于当前的默认选择界面。
借助可自定义的选择项,您可以实现无限可能。我特别喜欢这种 Airbnb 风格的国家/地区选择器,因为它采用了一种巧妙的自适应设计风格。借助即将推出的可设置样式的选择器,您可以实现上述功能以及更多功能,这使其成为 Web 平台上非常需要的补充。
演示视觉效果
实时演示
专属手风琴式折叠视图
解决选择样式(以及随之而来的所有问题)并不是 Chrome 团队一直以来唯一关注的界面组件。第一个新增组件更新是能够创建排他性手风琴,即手风琴中一次只能打开一个项目
Browser Support
启用此功能的做法是为多个详细信息元素应用相同的名称值,从而创建一个关联的详细信息组,这与一组单选按钮非常相似
<details name="learn-css" open>
<summary>Welcome to Learn CSS!</summary>
</details>
<details name="learn-css">
<summary>Box Model</summary>
<p>...</p>
</details>
<details name="learn-css">
<summary>Selectors</summary>
<p>...</p>
</details>
:user-valid和:user-invalid
另一项界面组件改进是 :user-valid 和 :user-invalid 伪类。:user-valid 和 :user-invalid 伪类最近在所有浏览器中都处于稳定状态,它们的行为与 :valid 和 :invalid 伪类类似,但仅在用户与输入内容进行过显著互动后才匹配表单控件。这意味着,只需编写极少的代码即可确定表单值是否已被互动或是否已变为“脏”,这对于提供用户反馈非常有用,并且减少了过去需要编写的大量脚本。
演示版抓屏
实时演示
input:user-valid,
select:user-valid,
textarea:user-valid {
--state-color: green;
--bg: linear-gradient(...);
}
input:user-invalid,
select:user-invalid,
textarea:user-invalid {
--state-color: red;
--bg: linear-gradient(...);
}
详细了解如何使用 user-* 表单验证伪元素。
field-sizing: content
最近推出的另一项实用的组件更新是 field-sizing: content,它可以应用于输入和文本区域等表单控件。这样一来,输入的大小就可以根据其内容而增大(或缩小)。field-sizing: content 对于文本框来说尤其方便,因为您不再需要使用固定大小的文本框,这样一来,您就不必向上滚动才能在过小的输入框中看到之前在提示中写的内容。
演示版抓屏
实时演示
textarea, select, input {
field-sizing: content;
}
详细了解字段大小调整。
<hr>(<select>)
能够启用选择中的 <hr> 或水平线元素是另一个虽小但很有用的组件功能。虽然此元素没有太多的语义用途,但它确实有助于您很好地分隔选择列表中的内容,尤其是您可能不一定想与 optgroup 分组的内容(例如占位值)。
选择屏幕截图
选择“实时演示”
<select name="majors" id="major-select">
<option value="">Select a major</option>
<hr>
<optgroup label="School of Fine Arts">
<option value="arthist">
Art History
</option>
<option value="finearts">
Fine Arts
</option>
...
</select>
详细了解如何在选择器中使用 hr
用户体验优化
我们一直在不断迭代,这不仅适用于互动和组件。过去一年中还推出了许多其他提升用户体验的更新。
使用前瞻进行嵌套
原生 CSS 嵌套已于去年在所有浏览器中推出,此后又进行了改进,以支持预读,这意味着元素名称之前的 & 不再是必需的。这使得嵌套操作更加符合人体工程学,与我过去习惯的操作类似。
我最喜欢 CSS 嵌套的一点是,它使您能够直观地屏蔽组件,并在这些组件中包含状态和修饰符,例如容器查询和媒体查询。以前,我习惯于将所有这些查询分组放在文件底部,以提高特异性。现在,您可以将它们写在代码的其余部分旁边,以便于理解
.card {
/* card base styles */
h2 {
/* child element style */
}
&.highlight {
/* modifier style */
}
&:hover, &:focus {
/* state styles */
}
@container (width >= 300px) {
/* container query styles */
}
}
块布局的 align-content
另一个非常好的变化是,能够在块布局中使用 align-content 等居中机制。这意味着,您现在可以在 div 中实现垂直居中等效果,而无需应用 flex 或网格布局,也不会产生阻止边距折叠等副作用,而这些副作用可能是您不希望从这些布局算法中获得的。
Browser Support
屏幕截图
实时演示
div {
align-content: center;
}
Text-wrap: balance 和 pretty
说到布局,文本布局通过添加 text-wrap: balance 和 pretty 得到了不错的改进。text-wrap: balance 用于实现更均匀的文本块,而 text-wrap: pretty 则侧重于减少文本最后一行中的单字。
演示版抓屏
实时演示
balance 和 pretty 对标题和段落的影响。尝试将演示翻译成其他语言!h1 {
text-wrap: balance;
}
详细了解 text-wrap: balance。
国际排版更新
CJK 文字功能的排版布局更新在过去一年中获得了许多不错的更新,例如 word-break: auto-phrase 功能,该功能可在自然短语边界处换行。
Browser Support
word-break: normal 和 word-break: auto-phrase 的比较而 text-spacing-trim 则会在标点符号之间应用字距调整,以提高中文、日语和韩语排版的易读性,从而获得更令人满意的视觉效果。
相对颜色语法
在颜色主题设置方面,我们看到相对颜色语法带来了重大更新。
在此示例中,此处的颜色使用基于 Oklch 的主题。随着色调值根据滑块进行调整,整个主题也会随之变化。这可以通过相对颜色语法来实现。背景使用基于色调的主要颜色,并调整亮度、色度和色调通道以调整其值。--i 是值渐变列表中同级元素的索引,用于展示如何将步进与自定义属性和相对颜色语法相结合来构建主题。
演示版抓屏
实时演示
balance 和 pretty 对标题和段落的影响。尝试将演示翻译成其他语言!:root {
--hue: 230;
--primary: oklch(70% .2 var(--hue));
}
li {
--_bg: oklch(from var(--primary)
calc(l - (var(--i) * .05))
calc(c - (var(--i) * .01))
calc(h - (var(--i) + 5)));
}
light-dark() 函数
随着 light-dark() 函数的推出,主题设置变得更加动态和简化。
light-dark() 函数是一项人体工程学改进,可简化颜色主题设置选项,让您能够以更简洁的方式编写主题样式,正如 Adam Argyle 在此直观图表中出色展示的那样。以前,您需要使用两个不同的代码块(默认主题和用户偏好设置查询)来设置主题选项。现在,您可以使用 light-dark() 函数在同一行 CSS 中为浅色主题和深色主题编写这些样式选项。
light-dark() 的可视化图表。如需了解详情,请参阅演示。
html {
color-scheme: light dark;
}
button {
background-color: light-dark(lightblue, darkblue);
}
如果用户选择了浅色主题,按钮将采用浅蓝色背景。 如果用户选择了深色主题,按钮将采用深蓝色背景。
:has() 选择器
如果不提及去年最令人印象深刻的互操作性亮点之一,我就失职了,那就是 :has() 选择器,它于去年 12 月在各个浏览器中推出。此 API 彻底改变了编写逻辑样式的方式。
借助 :has() 选择器,您可以检查子元素是否具有特定子元素,或者这些子元素是否处于特定状态,并且该选择器基本上也可以充当父级选择器。
has() 来设置 Tokopedia 上的比较块的样式。:has() 已证明对许多公司(包括 PolicyBazaar)特别有用,这些公司使用 :has() 根据内部内容设置块的样式,例如在比较部分,如果块中有要比较的方案,或者块为空,则样式会进行调整。
“借助 :has() 选择器,我们能够消除基于 JavaScript 的用户选择验证,并将其替换为 CSS 解决方案,该解决方案可无缝运行,并提供与之前相同的体验。–Aman Soni,PolicyBazaar 技术主管”
容器查询
Web 的另一项重要新增功能是容器查询,目前已推出并正被广泛使用。容器查询可用于查询元素的父元素的固有大小,以便应用样式。与只能查询视口大小的媒体查询相比,容器查询的粒度更细。
Angular 最近在 angular.dev 上推出了一个美观的新文档网站,该网站使用容器查询根据标题块在页面上的可用空间来设置标题块的样式。因此,即使布局发生变化,从多列边栏布局变为单列布局,标题块也可以自行调整。
如果没有容器查询,很难实现类似的效果,而且会损害性能,需要使用调整大小观察器和元素观察器。现在,根据父元素的大小设置元素样式非常简单。
演示版抓屏
实时演示
@property
最后,我们很高兴看到 @property 即将登陆 Baseline。这是一项关键功能,可为 CSS 自定义属性(也称为 CSS 变量)提供语义含义,并实现一系列新的互动功能。@property 还可在 CSS 中实现上下文含义、类型检查、默认值和回退值。为范围样式查询等更强大的功能打开了大门。这是一项以前从未实现过的功能,现在为 CSS 语言提供了如此多的深度。
演示版抓屏
实时演示
@property --card-bg {
syntax: "<color>";
inherits: false;
initial-value: #c0bae8;
}
总结
随着所有这些强大的新界面功能在各个浏览器中推出,我们能做的事情将是无限的。借助滚动驱动的动画和视图过渡,打造新颖的互动体验,让网页以我们前所未见的方式变得更加流畅和互动。借助新一代界面组件,您可以比以往更轻松地构建强大的精美自定义组件,而无需完全舍弃原生体验。最后,在架构、布局、排版和自适应设计方面改进生活质量不仅解决了小问题,也为开发者提供了构建复杂界面的工具,这些界面可在各种设备、不同规格的设备上运行,并满足各种用户需求。
借助这些新功能,您应该能够移除第三方脚本,以实现性能密集型功能,例如滚动叙事和使用锚点定位将元素相互关联,构建流畅的页面过渡效果,最终以原生方式设置下拉菜单的样式并改进代码的整体结构。
现在是成为 Web 开发者的最佳时机。自 CSS3 发布以来,还没有出现过如此多的活力和兴奋感。我们过去一直需要但只能梦想的功能,终于成为现实,并成为平台的一部分。正是因为有您的反馈,我们才能确定优先事项,并最终实现这些功能。我们正努力让您更轻松地完成繁琐的本地化工作,以便您有更多时间来打造重要内容,例如让您的品牌脱颖而出的核心功能和设计细节。
如需详细了解这些新功能,请访问 developer.chrome.com 和 web.dev,我们的团队会在这些网站上分享 Web 技术的最新资讯。欢迎试用滚动驱动的动画、视图过渡、锚定定位,甚至可设置样式的选择器,并与我们分享您的想法。我们随时乐意听取您的意见,也随时竭诚为您服务。