Google IO 2022——CSS 状态(上)https://developer.aliyun.com/article/1410893
8. COLRv1 字体
在 COLRv1 字体之前,Web 有 OT-SVG 字体,这也是一种开放格式,用于渐变字体、内置颜色和效果。不过,它们可能会变得非常大,虽然它们允许编辑文本,但定制的空间不大。
在 COLRv1 字体之后,Web 具有更小的占用空间、矢量可缩放、可重新定位、渐变功能和混合模式驱动的字体,它们接受参数来自定义每个用例的字体或匹配主题。
下面是 Chrome Developer 博客文章中有关表情符号的示例。 也许你已经注意到,如果你放大表情符号的字体大小,它就不会保持清晰。 这是一个图像,而不是矢量艺术。 使用 COLRv1 字体,表情符号既矢量又漂亮:图标字体可以用这种格式做一些惊人的事情,提供自定义的双色调调色板等等。 加载 COLRv1 字体就像任何其他字体文件一样:
@import url(https://fonts.googleapis.com/css2?family=Bungee+Spice);
自定义 COLRv1 字体使用 @font-palette-values
完成的,这是一个特殊的 CSS 规则,用于将一组自定义选项分组和命名为一个包以供以后参考。 指定自定义名称就像自定义属性一样,以 --
开头:
@import url(https://fonts.googleapis.com/css2?family=Bungee+Spice); @font-palette-values --colorized { font-family: "Bungee Spice"; base-palette: 0; override-colors: 0 hotpink, 1 cyan, 2 white; }
使用 --colorized
作为自定义的别名,最后一步是将调色板应用于使用颜色字体系列的元素:
@import url(https://fonts.googleapis.com/css2?family=Bungee+Spice); @font-palette-values --colorized { font-family: "Bungee Spice"; base-palette: 0; override-colors: 0 hotpink, 1 cyan, 2 white; } .spicy { font-family: "Bungee Spice"; font-palette: --colorized; }
随着越来越多的可变字体和彩色字体的出现,网页排版正朝着丰富的定制和创造性表达的方向发展。
相关资源:
- Github:github.com/googlefonts…
- Chrome Developers:developer.chrome.com/blog/colrv1…
- BlinkOn developer explainer video:www.youtube.com/watch?v=Bmq…
9. 视口单位
在新的视口变体之前,web提供了物理单位来帮助适应视口。 有高度、宽度、最小尺寸 (vmin) 和最大边 (vmax)。 这些对很多事情都有效,但移动浏览器带来了复杂性。
在移动设备上,加载页面时,会显示带有 url 的状态栏,此栏会占用部分视口空间。 在几秒钟和一些交互之后,状态栏可能会滑开,以便为用户提供更大的视口体验。 但是当该条滑出时,视口高度发生了变化,任何 vh 单位都会随着目标大小的变化而移动和调整大小。 在后来的几年里,vh 单位特别需要决定要使用两种视口尺寸中的哪一种,因为这会在移动设备上造成不和谐的视觉布局问题。 已确定 vh 将始终代表最大的视口。
.original-viewport-units { height: 100vh; width: 100vw; --size: 100vmin; --size: 100vmax; }
在新的视口变体之后,可以使用小型、大型和动态视口单位,并在物理视口单元的基础上添加逻辑等效单位。 这个想法是让开发人员和设计人员能够选择他们想要在给定场景中使用的单位。当状态栏消失时,也许可以稍微改变一下不协调的布局,这样就可以不用担心使用dvh(动态视口高度)。
以下是新视口变体提供的所有新视口单位选项的完整列表
/* 高度视口单位 */ .new-height-viewport-units { height: 100vh; height: 100dvh; height: 100svh; height: 100lvh; block-size: 100vb; block-size: 100dvb; block-size: 100svb; block-size: 100lvb; } /* 宽度视口单位 */ .new-width-viewport-units { width: 100vw; width: 100dvw; width: 100svw; width: 100lvw; inline-size: 100vi; inline-size: 100dvi; inline-size: 100svi; inline-size: 100lvi; } /* 最小视口单位 */ .new-min-viewport-units { --size: 100vmin; --size: 100dvmin; --size: 100svmin; --size: 100lvmin; } /* 最大视口单位 */ .new-max-viewport-units { --size: 100vmax; --size: 100dvmax; --size: 100svmax; --size: 100lvmax; }
希望这些将为开发人员和设计人员提供实现其视口响应式设计所需的灵活性。
相关资源:
- Spec:drafts.csswg.org/css-values-…
- The Large, Small, and Dynamic Viewports:www.bram.us/2021/07/08/…
10. :has()
浏览器支持:
在 :has()
之前,选择器的主体总是在最后。 例如,这个选择器的主体是一个列表项:ul > li。 伪选择器可以改变选择器,但它们不会改变主体:ul > li:hover
或 ul > li:not(.selected)
。
在 :has() 之后,元素树中较高的主体可以保留为主体,同时提供有关子项的查询:ul:has(> li)
。 很容易理解 :has(
) 是如何获得“父选择器”的通用名称的,因为在这种情况下,选择器的主体现在是父级。
这是一个基本语法示例,其中 .parent
类仍然是主体,但仅在子元素具有 .child
类时才被选中:
.parent:has(.child) {...}
这是一个示例,其中 元素是主体,但选择器仅在其中一个子元素具有 :focus-visible
时才匹配:
section:has(*:focus-visible) {...}
:has()
选择器开始成为一个神奇的实用工具,因为实际用例变得更加明显。例如,当前无法在包装图像时选择标签,因此很难确定锚定标记在该用例中如何更改其样式。可以使用
:has()
实现:
a:has(> img) {...}
figure:has(figcaption) img {...}
使用 @supports
及其 selector()
函数使检查支持变得简单,该函数在使用之前测试浏览器是否支持该语法:
@supports (selector(:has(works))) {
/* safe to use :has() */}
- Spec:www.w3.org/TR/selector…
- MDN:developer.mozilla.org/docs/Web/CS…
- The CSS :has() selector is way more than a "parent selector":www.bram.us/2021/12/21/…
2022年及以后的功能
在所有这些令人惊叹的功能在 2022 年登陆之后,仍有许多事情将难以完成。下面来介绍一些剩余的问题以及正在积极开发的解决方案。 这些解决方案是实验性的,即使它们可能在浏览器的标志后面被指定或可用。
1. 松散类型的自定义属性
浏览器支持:
CSS 自定义属性是惊人的。 它们允许将各种事物存储在命名变量中,然后可以对其进行扩展、计算、共享等。 事实上,它们是如此灵活,如果有一些不太灵活的东西会更好。
考虑一个场景,其中长方体阴影使用自定义属性作为其值:
box-shadow: var(--x) var(--y) var(--blur) var(--spread) var(--color);
这一切都会正常运行,直到任何一个属性更改为 CSS 不接受的值,例如 --x: red
。 如果任何一个嵌套变量丢失或设置为无效的值类型,则整个阴影会中断。
这就是@property
的用武之地:--x
可以成为一个类型化的自定义属性,不再松散和灵活,但在某些定义的边界下是安全的:
@property --x { syntax: '<length>'; initial-value: 0px; inherits: false; }
现在,当 box-shadow
中的var(--x)
使用 --x: red
时,red 将被忽略,因为它不是 。 这意味着阴影会继续正常工作,即使为其自定义属性之一提供了无效值。 它没有失败,而是恢复到其初始值
0px
。
除了类型安全之外,它还为动画打开了许多大门。 CSS 语法的灵活性使得某些动画变得不可能,比如渐变。 @property
在这里会很有用,因为类型化的 CSS 属性可以告知浏览器开发人员在其他过于复杂的插值中的意图。 它本质上限制了可能性的范围,以至于浏览器可以为以前无法实现的样式的各个方面设置动画。
考虑下面的例子,其中使用径向渐变来制作覆盖的一部分,从而创建聚光灯聚焦效果。按下alt/opt
键时,JavaScript设置鼠标x
和y
,然后将焦点大小更改为较小的值,例如25%
,在鼠标位置创建聚光灯焦点圆
.focus-effect { --focal-size: 100%; --mouse-x: center; --mouse-y: center; mask-image: radial-gradient( circle at var(--mouse-x) var(--mouse-y), transparent 0%, transparent var(--focal-size), black 0% ); }
不过,渐变无法设置动画。它们对于浏览器来说太灵活和太复杂了,无法理解你希望它们如何制作动画。 但是,使用@property
,可以单独设置一个属性并为其设置动画,浏览器可以轻松理解其意图。
使用这种聚焦效果的电子游戏始终会为圆设置动画,从一个大圆到一个针孔圆。下面是如何在演示中使用@property
,以便浏览器为渐变遮罩设置动画:
@property --focal-size { syntax: '<length-percentage>'; initial-value: 100%; inherits: false; } .focus-effect { --focal-size: 100%; --mouse-x: center; --mouse-y: center; mask-image: radial-gradient( circle at var(--mouse-x) var(--mouse-y), transparent 0%, transparent var(--focal-size), black 0% ); transition: --focal-size .3s ease; }
浏览器现在能够为渐变大小设置动画,因为我们已将修改的表面积减少到只有一个属性并设置值,以便浏览器可以智能地插入长度。
相关资源:
- Spec:www.w3.org/TR/css-prop…
- MDN:developer.mozilla.org/docs/Web/CS…
- web.dev:web.dev/at-property…
- Zoom demo:codepen.io/argyleink/p…
- CSS Tricks:css-tricks.com/exploring-p…
2. 媒体查询范围
在媒体查询范围之前,CSS 媒体查询使用 min-width
和 max-width
来表达条件。 它可能看起来像这样:
@media (min-width: 320px) { … }
在媒体查询范围之后,相同的媒体查询可能如下所示:
@media (320px >= width) {
…}
使用 min-width
和 max-width
的 CSS 媒体查询可能如下所示:
@media (min-width: 320px) and (max-width: 1280px) {
…}
在媒体查询范围之后,相同的媒体查询可能如下所示:
@media (320px <= width <= 1280px) {
…}
后者看起来会比前者更清晰。 由于规范的增加,开发人员将能够选择他们喜欢的,甚至可以互换使用它们。
相关资源:
- Spec:www.w3.org/TR/mediaque…
- MDN:developer.mozilla.org/docs/Web/CS…
- PostCSS plugin:github.com/postcss/pos…
3. 自定义媒体查询
在@custom-media
之前,媒体查询必须一次又一次地重复,或者依赖预处理器在构建期间基于静态变量生成正确的输出。
在@custom-media
之后,CSS允许对媒体查询进行定义别名和引用,就像自定义属性一样。
命名非常重要:它可以使目的与语法保持一致,使事物更易于共享,更易于在团队中使用。 以下是一些自定义媒体查询:
@custom-media --OSdark (prefers-color-scheme: dark); @custom-media --OSlight (prefers-color-scheme: light); @custom-media --pointer (hover) and (pointer: coarse); @custom-media --mouse (hover) and (pointer: fine); @custom-media --xxs-and-above (width >= 240px); @custom-media --xxs-and-below (width <= 240px);
现在它们已定义,我可以像这样使用其中一个:
@media (--OSdark) { :root { … } }
相关资源
- Spec:www.w3.org/TR/mediaque…
- PostCSS plugin:github.com/postcss/pos…
4. 嵌套选择器
在 @nest
之前,样式表中有很多重复。当选择器很长且每个选择器都针对微小的差异时,它变得特别笨拙。所以,我们会经常使用预处理器的嵌套功能。
在 @nest
之后,重复就消失了。 几乎所有支持预处理器的嵌套功能都将内置在 CSS 中。
article { color: darkgray; } article > a { color: var(--link-color); } /* with @nest becomes */ article { color: darkgray; & > a { color: var(--link-color); } }
除了避免重复的代码,嵌套最重要的是样式上下文保留在一个样式块中。 读者无需从一个选择器及其样式跳到另一个带有样式的选择器(示例 1),而是可以留在文章的上下文中并查看文章在其中拥有链接。
考虑一个子组件,它希望在不同的父级上下文中调整自己,而不是父组件拥有样式并更改子组件:
/* parent owns this, adjusting children */ section:focus-within > article { border: 1px solid hotpink; } /* with @nest becomes */ /* article owns this, adjusting itself when inside a section:focus-within */ article { @nest section:focus-within > & { border: 1px solid hotpink; } }
@nest 总体上有助于更健康的风格组织、集中化和所有权。 组件可以分组并拥有自己的样式,而不是让它们散布在其他样式块中。 在这些示例中,它可能看起来很小,但为了方便和易读性,它可以产生非常大的影响。
相关资源:
- Spec:www.w3.org/TR/css-nest…
- PostCSS plugin:github.com/csstools/po…
- The future of CSS: Nesting Selectors:www.bram.us/2019/03/17/…
5. 样式范围
在 @scope
之前,存在许多策略,因为 CSS 中的样式在默认情况下是级联、继承和全局作用域的。 CSS 的这些特性在很多方面都非常方便,但对于复杂的站点和应用程序,可能有许多不同样式的组件,级联的全局空间和性质会使样式感觉像是在泄漏。
在 @scope
之后,样式不仅可以限定在一个上下文中,就像一个类一样,它们还可以明确样式的结束位置,并且不会继续级联或继承。
在以下示例中,BEM 命名约定范围可以转换为实际意图。 BEM 选择器试图将 header
元素的颜色范围限定为具有命名约定的 .card
容器。 这要求header
上有这个类名,从而完成目标。 使用 @scope
,无需命名约定即可在不标记header
元素的情况下完成相同的目标:
.card__header { color: var(--text); } /* with @scope becomes */ @scope (.card) { header { color: var(--text); } }
下面是另一个例子,不特定于组件,更多的是关于 CSS 的全局范围性质。深色和浅色主题必须在样式表中共存,其中顺序在确定获胜风格时很重要。 通常这意味着深色主题样式出现在浅色主题之后; 这将浅色设置为默认样式,将深色设置为可选样式。 避免与 @scope
的排序和范围之争:
@scope (.light-theme) { a { color: purple; } } @scope (.dark-theme) { a { color: plum; } }
@scope
还允许建立样式范围的结束位置。 这不能通过任何命名约定或预处理器来完成;它很特别,只有浏览器内置的 CSS 才能做到。 在以下示例中,当 .media-block
的子项是 .content
的兄弟或父项时,将专门应用 img
和 .content
样式:
@scope (.media-block) to (.content) { img { border-radius: 50%; } .content { padding: 1em; } }
相关资源:
- Spec:www.w3.org/TR/css-scop…
- Explainer:css.oddbird.net/scope/expla…
6. 瀑布流布局
在使用Grid实现CSS瀑布流布局之前,JavaScript是实现瀑布流布局的最佳方式,因为任何带有列或flexbox的CSS方法都会不准确地表示内容顺序。使用grid构建CSS后,将不需要JavaScript库,内容顺序也将正确。
上图使用以下 CSS 实现:
.container { display: grid; grid-template-columns: repeat(4, 1fr); grid-template-rows: masonry; }
相关资源:
- Spec:drafts.csswg.org/css-grid-3/…
- MDN:developer.mozilla.org/docs/Web/CS…
- Smashing Magazine:www.smashingmagazine.com/native-css-…
7. CSS保存数据
在 prefers-reduced-data
媒体查询之前,JavaScript 和服务器可以根据用户的操作系统或浏览器的“data saver”选项更改其行为,但 CSS 不能。
在 prefers-reduced-data
媒体查询之后,CSS 可以加入用户体验增强,并在保存数据方面发挥作用。
css
复制代码
@media (prefers-reduced-data: reduce) {
picture, video { display: none; }}
在这个媒体滚动组件中使用了前面的CSS,节省了很多资源。根据访问视口的大小,可以在页面加载上节省更多资源。当用户与媒体滚动条交互时,继续保存。这些图像上都有load="lazy"
属性,再加上CSS完全隐藏元素,这意味着永远不会对图像发出网络请求。
对于我的测试,在一个中等大小的视口上,最初加载了 40 个请求和 700kb 的资源。 当用户滚动媒体选择时,会加载更多请求和资源。 使用 CSS prefers-reduced-data
媒体查询,加载了 10 个请求和 172kb 的资源。 这节省了半兆字节,用户甚至没有滚动任何媒体,此时没有其他请求。
这种减少数据体验的优势不仅仅是节省资源。 可以看到更多标题,并且没有分散注意力的封面图片来吸引注意力。 许多用户在数据保护模式下浏览,因为他们按每兆字节的数据付费——很高兴看到 CSS 能够在这里提供帮助。
相关资源:
- Spec:www.w3.org/TR/mediaque…
- MDN:developer.mozilla.org/docs/Web/CS…
- GUI Challenges:gui-challenges.web.app/media-scrol…
- Smashing Magazine:www.smashingmagazine.com/2021/12/cor…
8. 滚动快照
在这些滚动快照提案之前,需要编写自己的 JavaScript 来管理轮播、滑块或图库,并且可能会很复杂,需要所有的观察者和状态管理。 此外,如果不小心,自然滚动速度可能会被脚本标准化,使用户交互感觉有点不自然并且可能很笨拙。
(1)snapChanging()
浏览器一发布快照子项,就会触发此事件。这允许用户界面反映缺少快照子项和滚动条的不确定快照状态,因为它现在正在使用,并将在新的地方落地。
document.querySelector('.snap-carousel').addEventListener('snapchanging', event => { console.log('Snap is changing', event.snappedTargetsList); });
(2)snapChanged()
一旦浏览器捕捉到一个新的子对象,滚动条停止,就会触发此事件。这使得任何依赖于快照子对象的UI都可以更新并反映连接。
javascript
复制代码
document.querySelector('.snap-carousel').addEventListener('snapchanged', event => { console.log('Snap changed', event.snappedTargetsList); });
(3)scroll-start
滚动并不总是从一开始就开始。考虑一下可滑动组件,其中向左或向右滑动会触发不同的事件,或者页面加载时的搜索栏最初是隐藏的,直到滚动到顶部。这个CSS属性允许开发者指定一个滚动条应该从一个特定的点开始。
:root { --nav-height: 100px } .snap-scroll-y { scroll-start-y: var(--nav-height); }
(4):snap-target
这个 CSS 选择器将匹配滚动捕捉容器中当前被浏览器捕捉的元素。
.card { --shadow-distance: 5px; box-shadow: 0 var(--shadow-distance) 5px hsl(0 0% 0% / 25%); transition: box-shadow 350ms ease; } .card:snapped { --shadow-distance: 30px; }
在这些滚动快照提案之后,制作滑块、轮播或图库要容易得多,因为浏览器现在为任务提供了便利,消除了观察者和滚动编排代码,有利于使用内置 API。
这些 CSS 和 JS 功能还处于早期阶段,但请留意可以帮助尽快采用和测试它们的 polyfill。
相关资源:
- Draft spec:drafts.csswg.org/css-scroll-…
- Explainers:github.com/argyleink/S…
- Snap demos:snap-gallery.netlify.app/
9. CSS状态
在 toggle()
之前,只有浏览器内置的状态才能用于样式和交互。 例如,复选框输入具有 :checked
,这是一种内部管理的浏览器状态,用于 CSS 能够用于视觉更改元素的输入。
在 toggle()
之后,可以在任何元素上创建自定义状态,以便 CSS 更改和用于样式。 它允许循环、定向切换等。
在以下示例中,实现了与完整列表项删除线相同的效果,但没有任何复选框元素:
<ul class='ingredients'> <li>1 banana <li>1 cup blueberries ... </ul>
以及相关的 CSS toggle()
样式:
li { toggle-root: check self; } li:toggle(check) { text-decoration: line-through; }
如果你熟悉状态机,可能会注意到 toggle()
有多少交叉。 这个特性将让开发人员将更多的状态构建到 CSS 中,希望能以更清晰、更语义化的方式来编排交互和状态。
相关资源:
- Draft:tabatkins.github.io/css-toggle/
- The Future of CSS: CSS Toggles:www.bram.us/2022/04/20/…
10. 自定义选择元素
在 之前,CSS 无法使用丰富的 HTML 自定义
元素或更改选项列表的显示方式。 这导致开发人员加载外部库,这些库重新创建了
的大部分功能,这最终导致了大量工作。在 之后,开发人员可以为选项元素提供丰富的 HTML,并根据需要对其进行样式设置,同时仍然满足可访问性要求并提供语义 HTML。在以下示例中,取自 解释器页面,创建了一个带有一些基本选项的新选择菜单:CSS可以针对元素的各个部分并设置其样式:相关资源:Spec: open-ui.org/prototypes/…Demo: microsoftedge.github.io/Demos/selec…11. 定位在 anchor() 之前,绝对位置和相对位置是为开发人员提供的位置策略,可以让子元素在父元素中移动。在 anchor() 之后,开发人员可以将元素定位到其他元素,无论它们是否是子元素。 它还允许开发人员指定要定位的边缘,以及创建元素之间位置关系的其他细节。相关资源:Explainer: github.com/MicrosoftEd…