CSS Intelligence: Speculating On The Future Of A Smarter Language
CSS已从纯表现性语言演变为具有日益增长逻辑能力的语言——这得益于容器查询、关系伪类和if()函数等功能。它是否仍然仅用于样式设计,还是正在变成更多的东西?Gabriel Shoyombo探讨了CSS多年来变得多么智能,它的发展方向,它解决的挑战,是否变得过于复杂,以及开发者如何应对这种转变。
从前,CSS纯粹是表现性的。它强制性地处理标记语言的字体、颜色、背景、间距和布局等样式。它是一种外观语言,做被要求的事情,从不思考或做决策。至少,当Håkon Wium Lie在1994年提出CSS,世界 Wide Web Consortium(W3C)两年后采用它时,这就是它的设计目的。
快进到今天,随着新功能的加入,很多事情发生了变化,还有更多功能正在路上,将样式语言转向更命令式的范式。CSS现在积极支持复杂的响应式和交互式用户界面。随着容器查询、关系伪类和if()函数等最新进展,这种曾经局限于表现领域的语言已经踏入了逻辑领域,减少了对迄今为止处理其逻辑方面的语言JavaScript的依赖。
这种转变提出了关于CSS及其未来对开发者有趣的问题。CSS有意识地在一段时间内仅保持在样式领域,但现在是否是改变的时候了?此外,CSS是否仍然像开始时一样是一种表现性语言,还是正在变成更多更大的东西?本文探讨了CSS多年来变得多么智能,它的发展方向,它解决的问题,是否变得过于复杂,以及开发者如何应对这种转变。
历史背景:CSS的有意简洁
对CSS历史的一瞥显示,这种语言诞生是为了将内容与表现分离,使网页更易于管理和维护。CSS的第一个官方版本CSS1于1996年发布,它引入了基本的样式功能,如字体属性、颜色、盒模型(内边距、外边距和边框)、尺寸(宽度和高度)、一些简单显示(无、块和内联)以及基本选择器。
两年后,CSS2推出,并通过定位、z-index、增强选择器、表格布局和用于不同设备的媒体类型等功能扩展了CSS可以样式化的HTML内容。然而,样式语言内部存在不一致,这个问题在2011年由CSS2.1解决,成为现代CSS的标准。它简化了网页创作和网站维护。
在CSS1和CSS2.1之间的几年里,CSS主要是静态和声明性的。开发者在项目中经历了挫折和突破的混合。由于缺乏像Flexbox和CSS Grid这样的直观布局,开发者依赖表格布局、定位或浮动的hacky替代方案来绕过复杂设计,尽管浮动最初设计用于文本围绕网页上的障碍物(通常是媒体对象)流动。结果,开发者面临容器折叠和意外换行行为的问题。尽管如此,基本样式是直观的。新手今天可以轻松学习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中引入的容器大小查询。
容器大小查询允许开发者基于其父容器的尺寸样式化元素。这对于基于组件的设计是一个巨大的胜利,因为它消除了将响应式样式硬塞到全局媒体查询中的需要。
|
|
容器样式查询通过允许您基于容器上设置的自定义属性(又称CSS变量)样式化元素,更进一步。
|
|
这些功能在CSS中很重要,因为它们解锁了上下文感知组件。按钮可以根据父级设置的–theme属性更改外观,而无需使用JavaScript或硬编码类。
if()函数:未来一瞥
CSS if()函数可能只是最激进的转变。当实现时(截至版本137,Chrome是唯一支持它的浏览器),它将允许开发者在属性声明中直接编写内联条件逻辑。想想CSS中的三元运算符。
|
|
这个假设行或伪代码(不是语法)如果–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属性允许视觉反馈和平滑动画,如“Bringing Interactivity To Your Website With Web Standards”中讨论的。
这还不是全部。切换手风琴和模态框以前存在于JavaScript领域,但今天,这可以通过新的强大CSS组合实现,如用于手风琴的 HTML标签或用于模态框的:target伪类。CSS还可以使用aria-label与content: attr(aria-label)处理工具提示,以及使用无线电输入和标签处理星级评分,如同一文章中详细说明的。
另一篇文章“5 things you can do with CSS instead of JavaScript”列出了功能,如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变得过于复杂——一种最初设计用于格式化文档的语言现在 juggling 逻辑树和样式计算。
分裂视角:CSS中的逻辑是有益还是有害?
虽然上一节中的证据倾向于边界模糊,但开发者之间存在重大争议。许多现代开发者认为CSS中的逻辑早就该有了。随着Web开发变得更加组件化,声明式样式的局限性变得更加明显,使支持者将逻辑视为 once purely styling language 的必要演变。
例如,在像React这样的前端库中,组件通常需要基于props或states的条件样式。开发者不得不凑合使用JavaScript或CSS-in-JS解决方案来处理这种情况,但事实是这些解决方案并不正确。它们引入复杂性并将样式和逻辑耦合。CSS和JavaScript在Web开发中 meant to have standalone concerns,但像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 meant to handle的事情,并认为这是不必要的。这反映了即使涉及JavaScript,也偏好使用CSS进行样式任务。这些开发者拥抱CSS的新功能,将其视为出于性能原因减少JavaScript依赖的一种方式。
其他人反对它。将逻辑引入CSS是一个 slippery slope,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上的讨论,也反映了这种分裂。像“Is it always better to use CSS when possible instead of JS?”这样的问题收到答案 favouring CSS for performance and simplicity,但其他人 argue JavaScript is necessary for complex scenarios,说明了持续的辩论。不要被愚弄。同意CSS在样式中比JavaScript表现更好可能看起来方便,但情况并非总是如此。
更智能的CSS而不失去其灵魂
CSS一直通过是声明性的、可访问的和目的驱动的而与成熟的编程语言(如JavaScript)分开。
如果CSS要变得更智能,挑战不在于为了自身利益而使其更强大,而是在不妥协其主要关注点的情况下发展它。
“那么,一个逻辑丰富但仍然声明式的CSS可能是什么样子?让我们找出答案。
条件规则(if, @when…@else)与 carefully introduced logic
CSS演变的一个主要前沿是通过if()函数和@when…@else at-rules引入原生条件,这些是CSS Conditional Rules Module Level 5规范的一部分。虽然仍处于早期草案阶段,这将允许开发者基于评估条件应用样式,而无需转向JavaScript或预处理器。与JavaScript的命令式性质不同,这些条件旨在保持逻辑 ingrained in CSS’s existing flow,与级联和特异性对齐。
更强大、有意的选择器
选择器一直是CSS的主要优势之一,以 targeted way扩展它们将使 declaratively express relationships and conditions without needing classes or scripts更容易。目前,: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逻辑或复杂类系统。
一个基本的设计问题现在是,我们是否可以在不使其像JavaScript的情况下赋予CSS权力。事实是,为了赋予CSS条件逻辑、强大选择器和作用域规则,我们不需要它 mirror JavaScript’s syntax or complexity。目标是声明式 expressiveness,给CSS更多意识和控制,同时保留其清晰、可读的性质,我们应该专注于 that。当做得正确时,更智能的CSS可以放大语言的优势而不是稀释它们。
真正的危险不是逻辑本身,而是 unchecked complexity that obscures the simplicity with which CSS was built。
注意事项和约束:为什么智能并不总是更好
推动更智能的CSS伴随着 significant trade-offs alongside control and flexibility。多年来,历史表明,向语言或框架或库添加新功能 most likely introduces complexity,不仅对新