2024年6月11日至13日,CSS 工作组 (CSSWG) 在西班牙科鲁尼亚举行了今年的第二次面对面会议,会议议程涵盖了 CSS 语言的诸多新特性和改进。继2023年带来嵌套、容器查询和样式查询以及has:
选择器等令人瞩目的进步之后,2024年将迎来更多突破性更新。无论像内联条件语句这样的新特性刚刚起步,还是长期项目即将收尾,2024年已经充满了令人兴奋的发展——而我们才刚刚进入7月份!
本文将分享一些在本次会议上探讨的、我认为最有趣和最重要的 CSS 新特性。需要注意的是,这并非会议讨论的精确记录,而是对会议中重点关注的 CSS 主要主题的概述。实际上,这些特性已经酝酿多年,讨论主要集中在具体案例和新增强功能上,而不是定义完整的规范;在一个会议中完成这项工作是不可能的。
您可以查看 CSSWG 会议议程上讨论的具体问题。
if()
函数的前景自从 CSS 自定义属性在 2016 年左右获得可靠的支持以来,人们就尝试了许多方法,在不依赖 JavaScript 的情况下根据自定义属性值应用特定样式。最早的条件样式解决方法之一是 Roman Komarov 在 2016 年的“CSS 变量的条件”中提出的。从那时起,许多其他的“技巧”都被记录下来,用于在 CSS 中进行条件声明(包括 Ana Tudor 在 CSS-Tricks 上提出的极其巧妙的方法)。事实上,CSSWG 成员 Lea Verou 在她最近的文章“CSS 中的内联条件语句,现在?”中列出了讨论和比较这些解决方法的完整列表。
可以肯定的是,社区一直渴望一种使用自定义属性应用样式的条件方法。如今,我们有了一个能够完成这项任务的样式查询规范,但它有一些与浏览器支持无关的限制。最大的限制是什么?我们无法直接设置被查询容器的样式,因此我们需要在 HTML 中围绕该容器添加某种包装元素。
<code><div style="--variant: info"> <p>Here is some good <strong>news</strong></p> </div></code>
……以及样式查询:
<code><div style="--variant: info"> <p>Here is some good <strong>news</strong></p> </div></code>
if()
函数可能的样子在 CSSWG 方面,早在 2018 年就讨论过添加 if()
函数。在今年 6 月 13 日——是的,六年后——CSSWG 决定开始为 CSS 开发 if()
函数。尽管它看起来不错,但至少在两年内不要指望在浏览器中看到 if()
!(这是 Lea 的非官方估计。)我们可能需要等待更长时间才能获得足够的浏览器支持,才能在生产环境中可靠地使用它。规范草案才刚刚开始,许多事情必须首先通过测试。作为参考,CSS 变量工作草案始于 2012 年,直到 2016 年才获得广泛的浏览器支持。
语法方面,if()
可能会借鉴 JavaScript 和其他编程语言的三元运算符,结构如下:
<code>.news-container { container-name: news-container; } @container news-container style(--variant: info) { p { color: blue; border: 1px solid blue; } }</code>
……其中 a 是我们正在检查的自定义属性,b 和 c 是可能的条件返回值。要检查样式,将使用内联样式 style(--my-property: value)
。
<code>if(a ? b : c)</code>
即使 CSS 中不使用 ?
,并且 :
在其他地方也有不同的含义,我认为这种语法是大多数人最熟悉的,更不用说它还允许无缝的条件链接。
<code>.forecast { background-color: if(style(--weather: clouds) ? var(--clouds-color): var(--default-color)); }</code>
if()
函数的改进尽管这些可能不会出现在初始版本中,但了解 if()
在现在和未来某个时间点可能发生的变化仍然很有趣:
style()
查询检查自定义属性,但我们也可以使用内联 media()
查询检查媒体特性,或者使用内联 support()
检查用户代理是否支持特定属性。<code>.forecast { background-color: if( style(--weather: clouds) ? var(--clouds-color): style(--weather: sunny) ? var(--sunny-color); style( --weather: rain) ? var(--rain-color): var(--default-color) ); }</code>
if()
中,例如,如果我们在 clamp()
或 round()
函数中,我们可以进行计算而无需 calc()
。去年,视图过渡 API 使我们能够在导航网页和状态之间创建无缝过渡。无需组件或框架,无需动画库——只需使用少量的 JavaScript 和纯 HTML 和 CSS 即可。视图过渡的第一个实现很久以前就已集成到浏览器中,但它基于 Chrome 定义的实验性函数,并且仅限于两个状态之间的过渡(单页视图过渡),而不支持不同页面之间的过渡(即多页视图过渡),而这正是我们大多数开发人员所渴望的。模仿原生应用程序行为的可能性令人兴奋!
这就是为什么 CSS 视图过渡模块级别 2 如此出色,也是为什么它是本文中介绍的所有 CSS 新增功能中最受我喜爱的原因。是的,此特性带来了开箱即用的跨页面无缝过渡,但真正重要的是它消除了实现此功能对框架的依赖。我们可以回溯到纯 CSS 和 JavaScript,而不是使用库——例如 React 一些路由库。
当然,在某些复杂程度上,视图过渡 API 可能力不从心,但对于我们只想进行页面过渡而无需承担引入框架的性能成本的无数情况来说,它非常出色。
当我们从同一来源导航到两个页面之间时,会触发视图过渡。在这种情况下,导航可能是单击链接、提交表单或使用浏览器按钮来回移动。相比之下,在同一来源页面之间使用搜索栏之类的操作不会触发页面过渡。
两个页面——我们要离开的页面和我们要导航到的页面——都需要使用 @view-transition
at-rule 并将 navigation
属性设置为 auto
来选择加入过渡:
<code><div style="--variant: info"> <p>Here is some good <strong>news</strong></p> </div></code>
当两个页面都选择加入过渡时,浏览器会对这两个页面进行“快照”,并将“之前”页面平滑地淡入“之后”页面。
在该视频中,您可以看到旧页面如何淡入新页面,这要归功于一整套新的伪元素,这些伪元素在过渡过程中持续存在,并使用 CSS 动画来产生效果。浏览器将使用唯一的 view-transition-name
属性对元素的快照进行分组,该属性在我们可以引用的过渡上设置唯一标识符,并且该标识符捕获在包含页面上所有过渡的 ::view-transition
伪元素中。
您可以将 ::view-transition
视为所有页面过渡的 :root
元素,它将同一默认动画上的所有页面过渡部分组合在一起。
<code>.news-container { container-name: news-container; } @container news-container style(--variant: info) { p { color: blue; border: 1px solid blue; } }</code>
请注意,每个过渡都位于一个 ::view-transition-group
中,该组包含一个 ::view-transition-image-pair
,而该对又包含“旧”和“新”页面快照。我们可以根据需要在其中添加任意数量的组,并且它们都包含一个带有两个快照的图像对。
快速示例:让我们使用 ::view-transition
“根”作为参数来选择页面上的所有过渡,并在旧快照和新快照之间创建滑动动画。
<code>if(a ? b : c)</code>
如果我们在页面之间导航,则整个旧页面将向左滑动,而整个新页面将从右侧滑入。但是我们可能希望阻止页面上的某些元素参与过渡,因为它们在页面之间持续存在,而其他所有内容都从“旧”快照移动到“新”快照。
这就是 view-transition-name
属性的关键所在,因为我们可以对某些元素进行快照,并将它们放入与其他所有内容分开的 ::view-transition-group
中,以便单独处理它们。
<code><div style="--variant: info"> <p>Here is some good <strong>news</strong></p> </div></code>
您可以在 GitHub 上找到它的实时演示。请注意,在我撰写本文时,浏览器支持仅限于 Chromium 浏览器(即 Chrome、Edge、Opera)。
对于跨文档视图过渡,我们有很多值得期待的事情。例如,如果我们有几个具有不同 view-transition-name
的元素,我们可以为它们提供一个共享的 view-transition-class
来在一个位置设置它们的动画样式——甚至可以使用 JavaScript 进一步自定义视图过渡,以检查页面是从哪个 URL 进行过渡并相应地进行动画处理。
在 CSS 中相对于另一个元素定位元素似乎是一件轻而易举的事情,但实际上需要根据一系列神奇数字来混合使用内边距属性(顶部、底部、左侧、右侧)才能获得正确的结果。例如,在悬停时在元素左侧弹出一个小工具提示可能在 HTML 中看起来像这样:
<code>.news-container { container-name: news-container; } @container news-container style(--variant: info) { p { color: blue; border: 1px solid blue; } }</code>
……以及使用当前方法的 CSS:
<code>if(a ? b : c)</code>
不得不更改元素的定位和内边距值并不是世界末日,但这确实感觉应该有一种更简单的方法。此外,最后一个示例中的工具提示非常脆弱;如果屏幕太小或我们的元素太靠左,则工具提示将隐藏或溢出屏幕边缘。
CSS 锚点定位是 CSSWG 会议上讨论的另一个新特性,它有望使这类事情变得容易得多。
基本思想是我们建立两个元素:
这样,我们就有一种更声明式的方法来关联一个元素并将其相对于锚定元素定位。
首先,我们需要使用新的 anchor-name
属性创建我们的锚点元素。
稍微更改一下我们的标记:
<code>.forecast { background-color: if(style(--weather: clouds) ? var(--clouds-color): var(--default-color)); }</code>
我们为其指定一个唯一的虚线缩进作为其值(就像自定义属性一样):
<code>.forecast { background-color: if( style(--weather: clouds) ? var(--clouds-color): style(--weather: sunny) ? var(--sunny-color); style( --weather: rain) ? var(--rain-color): var(--default-color) ); }</code>
然后,我们使用 position-anchor
属性以及 fixed
或 absolute
定位将 .tooltip
关联到 .anchor
。
<code>.my-element { width: if(media(width > 1200px) ? var(--size-l): var(--size-m)); }</code>
.tooltip
目前位于 .anchor
的顶部,但我们应该将其移动到其他位置以防止这种情况。移动 .tooltip
的最简单方法是使用新的 inset-area
属性。让我们假设 .anchor
位于 3×3 网格的中间,我们可以通过为其分配行和列来在网格中定位工具提示。
inset-area
属性为 .tooltip
在特定行和列中的位置采用两个值。它使用物理值(例如 left、right、top 和 bottom)以及根据用户的书写模式的逻辑值(例如 start 和 end)以及共享的 center 值进行计数。它还接受引用 x 和 y 坐标的值,例如 x-start 和 y-end。所有这些值类型都是表示 3×3 网格上空间的方法。
例如,如果我们希望 .tooltip
相对于锚点的右上角定位,我们可以像这样设置 inset-area
属性:
<code><div style="--variant: info"> <p>Here is some good <strong>news</strong></p> </div></code>
最后,如果我们希望我们的工具提示跨越网格的两个区域,我们可以使用 span-
前缀。例如,span-top
将 .tooltip
放置在网格的顶部和中心区域。如果我们希望跨越整个方向,我们可以使用 span-all
值。
我们没有锚点的示例问题之一是工具提示可能会溢出屏幕。我们可以使用另一个新属性(这次称为 position-try-options
)结合新的 inset-area()
函数来解决此问题。
(是的,有一个 inset-area
属性和一个 inset-area()
函数。这是我们必须记住的一个!)
position-try-options
属性接受逗号分隔的回退位置列表,用于当 .tooltip
溢出屏幕时。我们可以提供一系列 inset-area()
函数,每个函数都包含与 inset-area
属性相同的属性值。现在,每次工具提示超出屏幕时,都会“尝试”下一个声明的位置,如果该位置导致溢出,则会尝试下一个声明的位置,依此类推。
<code>.news-container { container-name: news-container; } @container news-container style(--variant: info) { p { color: blue; border: 1px solid blue; } }</code>
这是一个非常新颖的概念,需要一些时间来理解。CSSWG 成员 Miriam Suzanne 在一段非常值得观看的视频中与 James Stuckey Weber 坐下来讨论和尝试锚点定位。
如果您正在寻找 TL;DW,Geoff Graham 对该视频做了笔记。
为了简洁起见,这里没有介绍锚点定位的许多方面,特别是新的 anchor()
函数和 @try-position
at-rule。anchor()
函数返回锚点边缘的计算位置,这提供了对工具提示内边距属性的更多控制。@try-position
at-rule 用于定义要在 position-try-options
属性上设置的自定义位置。
我的直觉是,对于绝大多数用例来说,使用 inset-area
将足够强大。
前面我说过,本文不会对 CSSWG 会议上进行的讨论进行精确的复述,而只是对 CSS 的新规范的广泛介绍,由于其新颖性,这些规范必然会在这些会议上出现。甚至还有一些特性我们根本没有时间在本综述中进行审查,这些特性仍在讨论中(咳嗽,砌体)。
有一点可以肯定的是:规范不是在某个真空环境中在一两次会议上制定的;它需要数十位优秀的作者、开发人员和用户代理的共同努力,才能将我们每天在 CSS 工作中使用的内容——更不用说我们将来会使用的内容——变为现实。
我还有机会与 CSSWG 的一些优秀的开发人员交谈,我发现他们从会议中获得的最大收获很有趣。您可能会期望 if()
位于他们的列表顶部,因为这是社交媒体上正在讨论的内容。但 CSSWG 成员 Emilio Cobos 告诉我,例如,letter-spacing
属性本质上是有缺陷的,并且没有简单的解决方案可以解决它与 CSS 当前定义的 letter-spacing
和在浏览器中的使用方式相一致的问题。这包括将普通属性转换为简写属性可能对代码库造成危险的事实。
我们可能认为微不足道的每一个细节都会被仔细分析,以造福网络并出于对网络的热爱。而且,正如我前面提到的,这些事情并非在封闭的真空环境中发生。如果您对 CSS 的未来有任何兴趣——无论是跟上 CSS 的发展还是积极参与其中——请考虑以下任何资源。
以上是上次CSSWG会议之后,CSS的东西I&#039;的详细内容。更多信息请关注PHP中文网其他相关文章!