几周前,当 CSS 工作组 (CSSWG) 决定在 CSS 值模块级别 5 规范中添加一个 if()
条件 时,一些警报响了起来。 是 Lea Verou 在同一天发布的 X 帖子引起了我的注意。
CSS 的历史性的一天 😀🎉
— Lea Verou (@LeaVerou) 2024 年 6 月 13 日
如果您编写了其他人使用和/或设置样式的任何组件,您就会知道这有多么重要!
background: if(style(–variant: success), var(–green));
即使您没有编写,这也将允许诸如
padding: if(var(–2xl), 1em, var(–xl) or var(–m),… pic.twitter.com/cXeqwBuXvK
Lea 是 GitHub 问题 的发起者,该问题引发了讨论,而且巧合的是,或者说是冥冥之中,决议是在她的生日当天提出的。 那天一定很热闹! “你生日收到了什么礼物?” “哦,你知道的,只是一个被 CSS 规范接受的提案。” 太疯狂了,太疯狂了。
该被接受的提案为 CSSWG 开启了绿灯,使其可以着手研究这一想法,并有意传播一份规范草案,以便在最终成为推荐的 CSS 功能之前,进一步征求意见和考虑。 因此,这一切都需要很长时间才能实现,也就是说,如果它能够完全实现。
但根据条件要求应用样式的想法非常令人兴奋,值得早期研究。 我在 Lea 发布到 X 的同一天在我的博客上 记了一些关于它的笔记,并认为应该将它们整理到这里以备后用,同时总结自那时起出现的更多细节。
这不是一个新想法
许多提案都源于先前被拒绝的提案,if()
也不例外。 事实上,我们最近获得了几个允许进行条件样式设置的 CSS 功能——:has()
和 容器样式查询 是两个最明显的例子。 Lea 甚至引用了 2018 年的票据,它看起来很像被接受的提案。
有什么区别?
样式查询已经发布,我们可以简单地引用相同的条件语法(加上来自 Tab 的
Lea Verou,“CSS 中的内联条件?”@when
提案 的media()
和supports()
),而在 2018 年的提案中,条件的工作方式在很大程度上是未定义的。
我喜欢 Lea 指出 CSS 始终是条件语言的方式
朋友们……从一开始,CSS 就有条件。 每个选择器本质上都是一个条件!
Lea Verou,“CSS 中的内联条件?”
没错! 瀑布模型是评估选择器并将它们与页面上的 HTML 元素进行匹配的工具。 if()
带来的作用是使用选择器编写内联条件。
语法
它归结为以下内容
<if()> = if( <container-query>, [<declaration-value>]{1, 2} )
…其中
- 值可以嵌套以生成多个分支。
- 如果没有提供第三个参数,它将等效于空令牌流。
目前这一切都是概念性的,没有什么是板上钉钉的。 当 CSSWG 处理该功能时,我们可能会看到一些变化。 但是,就目前而言,该想法似乎围绕着指定条件以及设置两种声明的样式之一——一种作为“默认”样式,一种作为匹配发生时的“更新”样式。
.element {
background-color:
/* If the style declares the following custom property: */
if(style(--variant: success),
var(--color-green-50), /* Matched condition */
var(--color-blue-50); /* Default style */
);
}
在这种情况下,我们正在寻找一个 style()
条件,其中一个名为 --variant
的 CSS 变量被声明并设置为 success
值,并且
- …如果
--variant
设置为success
,我们将success
的值设置为--color-green-50
,它是一个映射到某个绿色色值的变量。 - …如果
--variant
未设置为success
,我们将success
的值设置为--color-blue-50
,它是一个映射到某个蓝色色值的变量。
默认样式是可选的,因此我认为在某些情况下可以省略它,从而提高可读性。
.element {
background-color:
/* If the style declares the following custom property: */
if(style(--variant: success),
var(--color-green-50) /* Matched condition */
);
}
上面的语法定义提到,除了匹配条件和默认样式之外,我们还可以支持第三个参数,该参数允许我们在条件中嵌套条件。
background-color: if(
style(--variant: success), var(--color-success-60),
if(style(--variant: warning), var(--color-warning-60),
if(style(--variant: danger), var(--color-danger-60),
if(style(--variant: primary), var(--color-primary)
)
),
)
);
哇,看起来那里发生了一些疯狂的“盗梦空间”! Lea 接着提出了一种语法,它将产生一个更加扁平的结构。
<if()> = if(
[ <container-query>, [<declaration-value>]{2} ]#{0, },
<container-query>, [<declaration-value>]{1, 2}
)
换句话说,嵌套条件更加扁平,因为它们可以在初始条件之外声明。 与之前相同的概念,但语法不同。
background-color: if(
style(--variant: success), var(--color-success-60),
style(--variant: warning), var(--color-warning-60),
style(--variant: danger), var(--color-danger-60),
style(--variant: primary), var(--color-primary)
);
因此,与其在一个 if()
语句中嵌套另一个 if()
语句,不如将所有可能的匹配条件都组合到一个语句中。
这一切都与样式查询相关
我们试图通过查询元素的样式来匹配 if()
条件。 没有相应的 size()
函数来查询尺寸——容器查询隐式地假设尺寸。
.element {
background: var(--color-primary);
/* Condition */
@container parent (width >= 60ch) {
/* Applied styles */
background: var(--color-success-60);
}
}
当我们调用 style()
函数时,容器查询就变成了样式查询。
.element {
background: orangered;
/* Condition */
@container parent style(--variant: success) {
/* Applied styles */
background: dodgerblue;
}
}
在我看来,在 if()
的上下文中看待样式查询更有意义。 没有 if()
,很容易质疑样式查询的一般用途。 但从这个角度来看,很明显样式查询是比容器查询本身大得多的图景的一部分。
关于 if()
语法,还有很多事情需要弄清楚。 例如,Tab Atkins 描述了一种可能导致混淆的场景,即匹配条件和默认样式参数是什么。 因此,谁知道最终会如何呢!
支持其他条件的条件
正如我们已经指出的,if()
远不是 CSS 中提供的唯一类型的条件检查。 编写检查其他条件(如 @supports
和 @media
)的内联条件语句会是什么样子?
在代码中
background-color: if(
supports( /* etc. */ ),
@media( /* etc. */ )
);
挑战在于容器支持尺寸查询。 正如前面提到的,没有明确的 size()
函数; 相反,它更像是一个匿名函数。
@andruud 在 GitHub 讨论中 简明扼要地描述了这一挑战
我不明白为什么我们不能使用
supports()
和media()
,但尺寸查询会导致布局循环,这很难甚至不可能检测到。 (这就是为什么我们最初需要对尺寸 CQ 进行目前限制的原因。)
“我们不能已经使用 [X] 方法做到这一点吗?”
当我们之前查看语法时,您可能已经注意到,if()
与自定义属性一样重要,因为它与条件有关。 几年来,出现了许多变通方法来模拟我们通过 if()
获得的结果,我们可以根据自定义属性是否等于 0
或 1
来有条件地设置其值,包括
- 使用自定义属性作为布尔值来应用样式或不应用样式,具体取决于它是否等于
0
或1
。(Ana 写了一篇关于此内容的精彩文章。) - 使用一个带空值的占位符自定义属性,当另一个自定义属性被设置时,该占位符自定义属性会被设置,即 Chris 所描述的 “自定义属性切换技巧”。
- 容器样式查询! 问题(除了缺乏实现之外)是容器只对它们的子元素应用样式,即它们不能在满足某个条件时将其自身应用样式,而只能对其内容应用样式。
Lea 在一篇名为 “CSS 中的内联条件语句,现在?” 的单独文章中深入探讨了这一点,文章中包含一个表格,对各种方法进行了概述和比较,我将在下面直接粘贴该表格。 解释充满了复杂的 CSS 术语,但对于理解对 if()
的需求以及它与我们多年来使用的巧妙“技巧”相比如何非常有用。
方法 | 输入值 | 输出值 | 优点 | 缺点 |
---|---|---|---|---|
二元线性插值 | 数字 | 定量 | 可以用作值的一部分 | 输出范围有限 |
切换 | var(--alias) (实际值太奇怪,无法直接公开) | 任何 | 可以用作值的一部分 | 需要别名的奇怪值 |
暂停动画 | 数字 | 任何 | 正常,分离的声明 | 接管 animation 属性瀑布模型怪异 |
类型磨练 | 关键字 | syntax 描述符支持的任何值 | 暴露的 APIGood 封装具有高度灵活性 | 必须将 CSS 插入到 light DOM 中 代码繁琐(虽然可以用构建工具自动化) 不支持 Firefox(不过正在改变) |
可变动画名称 | 关键字 | 任何 | 正常,分离的声明 | 在 Shadow DOM 之外不切实际,因为会发生名称冲突 接管 animation 属性瀑布模型怪异 |
Lea,生日快乐!
虽然迟了两周,但感谢你与我们分享你生日大餐的喜悦!🎂
参考文献
- 自定义属性上的内联条件的 MVP 是什么?(Lea Verou,GitHub 问题 #10064)
- CSS 中的内联条件?(Lea Verou)
- CSS 中的内联条件,现在?(Lea Verou)
除了不需要任何类似的东西之外,如果它被实现,这将是 CSS 糟糕的一天。CSS 的好处在于它仍然相对不受愚蠢程序员影响的影响,但添加这个将打开通往各种愚蠢事物的大门。
接下来你就会知道,一些混蛋会用 CSS 编写 Web 服务器,这将开启一个新的超抽象、难以理解的 UI 框架时代,这些框架将需要某种节点扩展才能运行,并且每次你进行更改时都需要重新启动 Web 服务器,进一步阻止开发人员真正学习 CSS。
如果那里有开发人员实际上认为这对 CSS 来说是一场胜利,那么他们可能不应该编写 CSS。坚持使用 Java 或 C,因为如果你靠它生活,你就不会知道如何编写布局。
它已经完成 https://dev.to/thormeier/dont-try-this-at-home-css-as-the-backend-what-3oih
我从来不需要在 css 中使用 if 条件。我认为这违背了 css 的本意,它应该是一个层叠样式表……层叠是这里的关键怪异之处。这进一步将一种简单而优美的语言复杂化,变成了它本不应该成为的东西。KISS
同意所有评论,对于完全无意义的抽象来说,这真是奇怪的炒作。
请问什么将设置 success 变量值是 true 还是 false?
是的,与目前用于切换类名或有条件地更改样式的代码相同。
这样做只会让开发人员在出现错误时不知所措,因为功能现在可能在 css 或代码中。
它还会让测试功能变得更加困难。
我的脑子疼!
但是,我多年来一直在我的 Sass 代码中使用条件语句。例如,将参数传递给 mixin,并测试它们的值。
希望这种原生行为有一天能成为现实……但不要创建某种“弗兰肯斯坦”语法来实现它。
其他一些评论涵盖了我讨厌在这个领域工作的大部分内容。它们目光短浅、固执己见、仅仅基于自己个人的需求,甚至有些人对其他人充满敌意。
你甚至尝试过从其他角度看待它吗?你尝试过在当前环境之外找到它的实际用例吗?其中一个好处可能是最终不再依赖某些类型的 CSS/JS 框架。这可能是迈向纯 Web 开发的下一步。迈向更易于实现的样式化 Web 组件。迈向更易于设置、完全可自定义的主题。迈向更 DRY、更紧凑的 CSS。
老实说,我看到了更多优点而不是缺点。我的缺点更多的是在性能和语法方面。但这些正是工作组存在的意义,要么解决这些问题,要么说“不,不值得努力”。
这些评论看起来像是对停滞的仓促呼吁;人们不欢迎改变。如果这种心态盛行,我们仍然会坐在 CRT 前,使用 bgcolor 属性并像 1990 年代后期和 2000 年代初期那样进行表格布局。啊,收回这句话!我们可能仍然用赭石颜料在洞穴墙壁上作画。
此外,关于上面提到的敌意评论:称他人为白痴、混蛋或愚蠢。真的吗?有人需要自我验证吗?
CSS 变得越来越不直观。如果几年前,那些精通 CSS 的人可以用一只手,最多两只手的手指来计算。现在你甚至可以假设没有这样的人。
他们把语法搞得乱七八糟。不要告诉我这是可读的代码:https://codepen.io/t_afif/pen/vYweZQa
我觉得读完这篇文章后需要洗个冷水澡。可能性令人难以置信。我的睡眠时间没了。
拜托。