CSS智能化:探索更智能语言的未来

本文深入探讨CSS从纯表现层语言向智能化发展的演变历程,分析容器查询、if()函数等新特性如何赋予CSS逻辑能力,并讨论这种转变对开发者、代码复杂度和Web开发未来的影响。

CSS Intelligence: Speculating On The Future Of A Smarter Language

CSS已经从纯表现层语言演变为具有越来越强逻辑能力的语言——这得益于容器查询、关系伪类和if()函数等特性。它仍然只是用于样式设计,还是正在变成更多的东西?Gabriel Shoyombo探讨了CSS这些年来变得有多智能,它的发展方向,它解决的挑战,是否变得过于复杂,以及开发者对这种转变的反应。

从前,CSS纯粹是表现性的。它强制处理标记语言的字体、颜色、背景、间距和布局等样式。它是一种外观语言,做被要求的事情,从不思考或做决定。至少,当Håkon Wium Lie在1994年提出CSS,两年后万维网联盟(W3C)采纳它时,它是为此而设计的。

快进到今天,随着新特性的加入,很多事情都发生了变化,还有更多特性正在将样式语言转向更命令式的范式。CSS现在主动支持复杂的响应式和交互式用户界面。随着容器查询、关系伪类和if()函数等最新进展,这种曾经局限于表现领域的语言已经踏入了逻辑领域,减少了对迄今为止处理其逻辑方面的语言JavaScript的依赖。

这种转变提出了关于CSS及其对开发者未来的有趣问题。CSS有意在一段时间内仅局限于样式领域,但现在是否是改变的时候了?此外,CSS是否仍然像开始时那样是一种表现性语言,还是正在变成更多更大的东西?本文探讨了CSS这些年来变得有多智能,它的发展方向,它解决的问题,是否变得过于复杂,以及开发者对这种转变的反应。

历史背景:CSS的有意简化

对CSS历史的一瞥显示,这种语言诞生是为了将内容与表现分离,使网页更易于管理和维护。CSS的第一个官方版本CSS1于1996年发布,它引入了基本的样式功能,如字体属性、颜色、盒模型(内边距、外边距和边框)、尺寸(宽度和高度)、一些简单的显示(无、块和内联)以及基本选择器。

两年后,CSS2推出,通过定位、z-index、增强的选择器、表格布局和用于不同设备的媒体类型等特性扩展了CSS可以样式化的HTML内容。然而,样式语言内部存在不一致性,这是CSS2.1在2011年解决的问题,成为现代CSS的标准。它简化了网页创作和网站维护。

在CSS1和CSS2.1之间的几年里,CSS基本上是静态和声明性的。开发者在项目中经历了挫折和突破的混合。由于缺乏像Flexbox和CSS Grid这样直观的布局,开发者依靠表格布局、定位或浮动的hack替代方案来绕过复杂的设计,尽管浮动最初设计用于文本围绕网页上的障碍物(通常是媒体对象)流动。因此,开发者面临容器折叠和意外换行行为的问题。尽管如此,基本样式是直观的。新手今天可以轻松学习Web开发,第二天添加基本样式。CSS与内容和逻辑分离,因此性能高且轻量。

CSS3:迈向上下文感知的第一步

当CSS3推出时,情况发生了变化。开发者期望像以前版本那样进行一次单一的整体更新,但他们的期望与最新版本的现实不符。CSS3红地毯揭示了一个模块化系统,具有强大的布局工具,如Flexbox、CSS Grid和媒体查询,首次定义了开发者如何建立响应式设计。拥有超过20个模块,CSS3标志着“更智能CSS”的开始。

Flexbox在2012年左右引入,提供了一个灵活的一维布局系统,而CSS Grid在2017年推出,通过提供二维布局框架将布局更进一步,使以最少代码实现复杂设计成为可能。正如Chris Coyier所讨论的,这些进展减少了对浮动等hack的依赖。

这并没有停止。媒体查询是CSS3的一个突出版本,是这种智能CSS的主要贡献者之一。借助媒体查询,CSS可以响应不同设备的屏幕,调整其样式以适应屏幕尺寸、宽高比和方向,这是早期版本无法轻易实现的壮举。在第五级中,它添加了用户偏好媒体功能,如prefers-color-scheme和prefers-reduced-motion,通过适应用户设置的样式使CSS更加以用户为中心,增强了可访问性。

CSS3标志着上下文感知CSS的开始。

上下文感知意味着能够理解并相应地响应你周围或环境中的情况。这意味着系统和设备可以感知关键信息,如你的位置、一天中的时间和活动,并相应调整。

在Web开发中,“上下文感知”一词一直与组件一起使用,但什么驱动了上下文感知组件?如果你提到组件样式以外的任何东西,那你就错了!要使组件被认为是上下文感知的,它需要感知其环境的存在并知道其中发生的事情。例如,要使你的网站更新其样式以适应黑暗模式界面,它需要知道用户的偏好。此外,要更改其布局,网站需要知道用户访问它的设备——多亏了用户偏好媒体查询,这是可能的。

尽管有这些特性,CSS在很大程度上仍然是反应性的。它响应外部因素,如屏幕尺寸(通过媒体查询)或输入状态(如:hover、:focus或:checked),但它从不基于环境变化做决定。开发者通常转向JavaScript来实现那种级别的交互。

然而,不再是这样了。

例如,借助容器查询,以及最近的容器样式查询,CSS现在不仅响应布局约束,还响应设计意图。它可以基于组件的环境甚至其父级的主题或状态进行调整。这还不是全部。最近规范的if()函数承诺内联条件逻辑,允许样式基于条件更改,所有这些都可以在没有脚本的情况下实现。

这些发展表明CSS正在超越表现来处理行为,挑战其传统角色。

推动智能化的新CSS特性

目前有几个特性正在将CSS推向动态和自适应的边缘,从而使其更智能,但这两个值得提及:容器样式查询和if()函数。

什么是容器样式查询,为什么它们重要?

为了更好地理解容器样式查询是什么,快速了解一下近亲是有意义的:CSS Containment Module Level 3中引入的容器大小查询。

容器大小查询允许开发者基于其父容器的尺寸来样式化元素。这对于基于组件的设计来说是一个巨大的胜利,因为它消除了将响应式样式硬塞到全局媒体查询中的需要。

1
2
3
4
5
6
/* 基于大小的容器查询 */
@container (min-width: 500px) {
  .card {
    flex-direction: row;
  }
}

容器样式查询通过允许你基于容器上设置的自定义属性(又称CSS变量)来样式化元素,更进一步。

1
2
3
4
5
6
7
/* 基于样式的容器查询 */
@container style(--theme: dark) {
  .button {
    background: black;
    color: white;
  }
}

这些特性在CSS中很重要,因为它们解锁了上下文感知组件。按钮可以基于父级设置的–theme属性更改外观,而无需使用JavaScript或硬编码类。

if()函数:窥见未来

CSS if()函数可能只是最激进的转变。当实现时(截至版本137,只有Chrome支持它),它将允许开发者在属性声明中直接编写内联条件逻辑。想想CSS中的三元运算符。

1
padding: if(style(--theme: dark): 2rem; else: 3rem);

这假设行或伪代码(不是语法)如果–theme变量等于dark,则将文本颜色设置为白色,否则设置为黑色。目前,if()函数在任何浏览器中都不支持,但它在CSS工作组的雷达上,并且有影响力的开发者如Lea Verou已经在探索其可能性。

新CSS:CSS和JavaScript之间的界限是否模糊?

传统上,关于样式化的关注点分离是这样的:CSS用于事物看起来如何,JavaScript用于事物行为如何。然而,像容器样式查询和规范的if()函数这样的特性开始模糊这条线。CSS开始行为化,不是在API调用或事件监听器的意义上,而是在基于逻辑或上下文有条件地应用样式的能力上。

随着Web开发的发展,CSS开始 encroach on JavaScript领域。CSS3带来了动画和过渡,这是交互式Web开发的强大组合,在早期没有JavaScript是不可能的。今天,研究证明CSS已经承担了以前由JavaScript处理的几个交互任务。例如,:hover伪类和transition属性允许视觉反馈和平滑动画,如“使用Web标准为您的网站带来交互性”中所讨论的。

这还不是全部。切换手风琴和模态框以前存在于JavaScript领域,但今天,这可以通过新的强大CSS组合实现,如用于手风琴的

HTML标签,或用于模态框的:target伪类。CSS还可以使用aria-label与content: attr(aria-label)处理工具提示,以及使用单选输入和标签处理星级评分,如同一篇文章中详细说明的。

另一篇文章“你可以用CSS而不是JavaScript做的5件事”列出了像scroll-behavior: smooth用于平滑滚动和@media (prefers-color-scheme: dark)用于黑暗模式的功能,这些任务曾经需要JavaScript。在同一篇文章中,你还可以看到,通过使用CSS滚动捕捉功能(我们甚至不是在谈论专门为仅用CSS创建轮播而设计的功能,最近在Chrome中原型化),可以在没有JavaScript的情况下创建轮播。

CSS向JavaScript领域的这些扩展现在使后者仅处理Web应用程序中复杂、关键的交互,如用户输入、进行API调用和管理状态。虽然CSS伪类如:valid和:invalid可以作为输入元素中的错误或成功指示器,但你仍然需要JavaScript进行动态内容更新、表单验证和实时数据获取。

CSS现在解决了许多开发者从未知道存在的问题。在许多样式场景中,JavaScript不再需要,开发者现在拥有简化的代码库。依赖更少,开销更低,网站性能更好,尤其是在移动设备上。事实上,这种转变使CSS倾向于更易访问的Web,因为CSS驱动的设计通常更容易被浏览器和辅助技术处理。

虽然新特性带来很多好处,但它们也引入了以前不存在的复杂性:

  • 当逻辑分布在CSS和JavaScript中时会发生什么?
  • 如果没有清晰视图显示什么触发了它们,我们如何调试条件样式?
  • CSS过去只处理基本样式,如颜色、字体、布局和间距,这对新开发者来说更容易上手。随着这些新特性需要理解曾经专属于JavaScript的概念,学习曲线变得多难?

开发者分裂了。虽然一些人欢迎更智能、更组件感知的Web的自然演变想法,但其他人担心CSS变得过于复杂——一种最初设计用于格式化文档的语言现在要处理逻辑树和样式计算。

分歧的观点:CSS中的逻辑是有益还是有害?

虽然上一节的证据倾向于边界模糊,但开发者之间存在重大争议。许多现代开发者认为CSS中的逻辑早就该有了。随着Web开发变得更加组件化,声明式样式的局限性变得更加明显,导致支持者将逻辑视为一种曾经纯粹样式语言的必要演变。

例如,在像React这样的前端库中,组件通常需要基于props或状态的条件样式。开发者不得不使用JavaScript或CSS-in-JS解决方案来处理这种情况,但事实是这些解决方案并不正确。它们引入了复杂性,并将样式和逻辑耦合在一起。CSS和JavaScript在Web开发中本应有独立的关注点,但像CSS-in-JS这样的库忽略了规则并将两者结合。

我们已经看到像SASS和LESS这样的预处理器证明了条件、循环和变量在样式中的有用性。不接受CSS in JavaScript方法的开发者已经 settled for these preprocessors。尽管如此,像Adam Argyle一样,他们表达了他们对原生CSS解决方案的需求。有了原生条件,开发者可以减少JavaScript开销,避免运行时类切换来实现条件呈现。

“对我来说,在JavaScript中操作样式设置从来感觉不对,当CSS是工作的正确工具时。借助CSS自定义属性,我们可以将需要来自JavaScript的内容发送到CSS。”——Chris Heilmann

此外,Bob Ziroll不喜欢使用JavaScript来处理CSS应该处理的事情,并认为这是不必要的。这反映了即使涉及JavaScript,也偏好使用CSS进行样式任务。这些开发者拥抱CSS的新功能,将其视为出于性能原因减少JavaScript依赖的一种方式。

其他人反对它。将逻辑引入CSS是一个滑坡,CSS可能通过变得太像编程语言而失去其核心优势——简单性、可读性和可访问性。担心的是开发者冒着使Web比应该的更复杂的风险。

“我是老派的。我喜欢我的CSS与HTML分开;我的HTML与JS分开;我的JS与CSS分开。”——Sara Soueidan

这种观点强调了传统的关注点分离,认为混合角色会使维护复杂化。此外,Brad Frost在 specifically talking about CSS-in-JS时也表达了怀疑, stating that it, “doesn’t scale to non-JS-framework environments, adds more noise to an already-noisy JS file, and the demos/examples I have seen haven’t embodied CSS best practices.” 这突出了对可扩展性和最佳实践的担忧,表明模糊的边界可能并不总是有益的。

社区讨论,如Stack Overflow上的讨论,也反映了这种分歧。像“是否总是更好在可能时使用CSS而不是JS?”这样的问题收到支持CSS性能和简单性的答案,但其他人认为JavaScript对于复杂场景是必要的,说明了持续的辩论。不要被愚弄。同意CSS在样式上比JavaScript表现更好可能看起来方便,但情况并非总是如此。

更智能的CSS而不失去其灵魂

CSS一直通过声明性、可访问性和目的驱动而与完整的编程语言(如JavaScript)区分开来。

如果CSS要变得更智能,挑战不在于为了自身而使其更强大,而是在发展时不妥协其主要关注点。

“那么,一个逻辑丰富但仍然声明性的CSS可能是什么样子?让我们找出答案。

条件规则(if, @when…@else)与谨慎引入的逻辑

CSS演变的一个主要前沿是通过if()函数和@when…@else at-rules引入原生条件,这些是CSS Conditional Rules Module Level 5规范的一部分。虽然仍处于早期草案阶段,但这将允许开发者基于评估的条件应用样式,而无需转向JavaScript或预处理器。与JavaScript的命令性性质不同,这些条件旨在将逻辑 ingrained in CSS的现有流程中,与级联和特异性对齐。

更强大、有意的选择器

选择器一直是CSS的主要优势之一,以有针对性的方式扩展它们将使更容易声明式地表达关系和条件,而无需类或脚本。目前,:has()让开发者基于子元素样式化父元素,而:nth-child(An+B [of S]?)(在Selectors Level 4中)允许更复杂的匹配模式。 together,它们允许更大的精度而不改变CSS的性质。

无JavaScript的作用域样式

开发者在像React或Vue这样的基于组件的框架中面临的挑战之一是样式作用域。样式作用域确保样式仅应用于特定元素或组件,并且不会泄漏。过去,要实现这一点,你需要实现BEM命名约定、CSS-in-JS或像CSS Modules这样的构建工具。CSS中的原生作用域样式,通过新的实验性@scope规则,允许开发者在特定上下文中封装样式,而无需额外工具。此特性使CSS更加模块化,而不将其绑定到JavaScript逻辑或复杂的类系统。

一个基本的设计问题现在是,我们是否可以在不使CSS像JavaScript的情况下赋予它权力。事实是,要赋予CSS条件逻辑、强大选择器和作用域规则,我们不需要它 mirror JavaScript的语法或复杂性。目标是声明式表达性,给CSS更多意识和控制,同时保留其清晰、可读的性质,我们应该专注于这一点。当做得正确时,更智能的CSS可以放大语言的优势而不是稀释它们。

真正的危险不是逻辑本身,而是 unchecked complexity that obscures the simplicity with which CSS was built.

注意事项和约束:为什么智能并不总是更好

推动更智能的CSS伴随着控制和灵活性的重大权衡。多年来,历史表明,向语言或框架或库添加新特性很可能引入复杂性,不仅对新

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计