我并不是要举起盾牌来保护 CSS 实用类框架。 我自己甚至不太喜欢这种方法,任何东西都不应该凌驾于公平的批评之上。 但“公平”是一个关键词。 我不知道自己见过多少次将实用类样式与内联样式进行比较。 Sarah Dayan 对此感到厌倦了
[...] 尽管多次尝试揭穿常见的谬误,但实用优先的爱好者们不得不不断地回复大量错误的观念。 而且,**最陈旧、最常用的老生常谈是,实用类仅仅是内联样式。**
我认为这个比较会让它变得清晰。
<div style="color: #3ea8ca;"></div>
<div class="color-blue"></div>
第一个 div 在 HTML 中直接设置了color
,这是一个非常具体的蓝色颜色值。 第二个的color
是在 HTML 外部设置的,使用类名,您可以在 CSS 中使用它来配置蓝色的色调。 当然,第二个类名相当有限,顾名思义,它只做一项工作,但它仍然提供了一些抽象,因为蓝色可以更改而无需更改标记。 使用大小实用类(例如size-xl
)也是同样的道理。 这也是一种抽象,我们可以使用它来定义使用该类名作为选择器的 CSS 中元素的填充。 但是,如果我们要直接在 HTML 中的元素上使用style="padding: 10px;"
,那将是一个绝对值,需要在标记中更改该值。
不过,公平地说(这就是我们追求的目标),实用类框架中有很多类的命名方式非常接近于内联样式的行为。 例如,Tailwind 中的top-0
表示top: 0
,并且没有关于它的配置或抽象。 这不像该类将在 CSS 中使用除零以外的任何值进行更新,因为该值在名称中。“实用”是对此的一个很好的描述。 它非常类似于内联样式。
所有这些可通过智能默认值进行配置的内容将基于实用类的框架置于不同的类别中。 内联样式对您如何设置样式没有任何限制(除了硬性限制,例如没有伪选择器或媒体查询),而有限的实用类集提供了很多样式限制。 这些约束通常是理想的,因为它们会导致设计看起来一致且美观,而不是不一致且凌乱。
借用我曾经在稍微不同的上下文中听到的一个隐喻:**基于实用类的框架就像保龄球的护栏一样。** 使用这些类,它就会正常工作。 您可能不会获得全中,但也不会得到沟球。
我在关于实用类框架的对话中听到的另一个不公平的批评是,**您会随它们一起发送更多 CSS。** 如果是这样,那么您肯定搞砸了。 在我看来,这种方法的主要目的是发送更少的 CSS(仅您使用的类)。 我第一个告诉您,一个能够准确且完美地做到这一点的构建过程很棘手,并且可能导致不健康的技术债务,但我将承认,如果您做对了,发送更少的 CSS 对性能有利。 Tailwind 特别鼓励并帮助您做到这一点。
所以,综上所述,我认为这种方法有很多东西可以批评。 例如,我个人不喜欢查看所有这些类。 我真的不喜欢。 我不是关于完美抽象类的绝对主义者,但是在一个 div 之后又一个 div 上看到 10 到 20 个类会妨碍我进行 HTML 模板化时想要做的事情。 它感觉更难重构。 它感觉更难看出语义上发生了什么。 更难解析该列表以查找我需要执行非样式操作的其他类。 我从实用程序中获得的一些优势(例如将样式范围限定到我需要的确切位置)通常可以通过其他工具获得。
我还认为,实用类框架在您拥有热模块替换的 JavaScript 组件设置中效果最佳。 否则,HTML 更改往往会触发整个页面刷新。 例如,像Browsersync这样的工具非常好。 当您的 CSS 更改时,它会执行 CSS 注入。 但它无法执行新的 HTML 注入;它只是刷新页面。 因此,如果没有热模块替换(通常不适用于您的通用 HTML 站点或静态站点生成器),您在创作时会获得更糟糕的DX。
我认为比较的重点是内联样式的问题与实用类相同。 显然,从语法上讲它们是不同的,但是您可以抽象“蓝色”的含义这一事实并没有真正解决(至少在我看来)内联样式的主要问题(即违反关注点分离和 DRY 原则)。 我的意思是,如果抽象确实是唯一的问题,您可以始终执行
在我看来,这并没有好多少,与以下内容也没有任何区别
它确实非常相似,但两者之间存在巨大差异。
它被称为内容安全策略,简称 CSP。
使用
style
会导致安全方面的立即失败,而使用类则完全没问题。顺便说一句,我不喜欢这两种方法,因为我觉得它在样式和内容之间创建了一个硬链接,在我看来,这对关注点分离不利。 我只想指出,使用
style
的缺点大于使用实用类。在我看来,实用 CSS 框架最适合与基于组件的框架一起使用。 我认为这就是您保持 DRY 的方式。
在使用 React 等工具时,我始终在组件及其样式之间进行一对一的映射,并且从不跨多个组件使用 CSS。
如果我有一个重复且需要看起来相同的 UI 模式(图标 + 文本、按钮等...),那么我只需将其提取为具有自身样式的可重用组件。
我认为在这种情况下,无论您是在单独的文件中声明 CSS、使用 Styled Components 还是使用实用 CSS 框架,实际上都没有太大区别,因为您的 CSS 无论如何都与单个 HTML 模板相关联。
我不认为这在规模上是可行的。 您真的需要为每个需要具有特定样式的 HTML 原语创建一个全新的组件吗? 似乎除了布局模板和组件之外,控制大多数内容的样式在样式表中会容易得多。 我不明白为什么
比以下内容更好
现在,如果我们谈论的是对唯一、可重用模式的真正抽象,那又是另一回事了。 我仍然偏爱语义类、关注点分离、样式表作为 SSoT 等,但恕我直言,这至少比为 HTML 和 CSS 免费提供的每个内容创建新组件要好。
同意 Jace Cotton 的观点。
此外:所谓的实用程序给开发人员带来了更多麻烦,您需要学习它们,但实际上 CSS 知识就足够了,因为实用程序 = 内联。
因此,有什么意义呢? 在编写类之前,先学习如何使用类。 您在所有页面上都有标题,所有页面上都需要 CSS => 使用外部 CSS。 您需要在一个页面上使用特定的 CSS,请使用内联或外部的附加样式表。 为什么你需要复杂化事情? 您计划添加 10 个模块,这意味着您需要重构您的方法并使用 10 个模块加上 1 个内联或外部 CSS 提供 1 个模块。 您想做一些动态的事情 = 混乱,因为您永远不应该让客户决定您的网站的外观 => 他们不是设计师,他们大多不知道自己想要什么等等。
我认为 Tailwind 非常出色地掌握了实用程序方法。
在我看来,实用类框架的两个最大权衡是它们使响应媒体查询变得麻烦,并且每个实用程序确实只需要做一件事。
我也不喜欢这种方法,但同样,像 Tailwind 这样的自动化解决方案很好地解决了它想要解决的问题。
在 HTML 中使用 Tailwind 非常适合原型设计或预定义类的细微变化,但不适合直接放在生产环境中,我建议在您的 CSS 中使用
@apply
,这样,您可以清理并合并公共样式,还可以使用 Browsersync 等工具。这就是我们所做的。 使用来自 Tailwind 的内联实用程序快速创建原型,然后使用 —-purge 保留我们需要的部分,到生产环境上线时,将使用 @apply 添加大部分类。 保持代码相对整洁,如果我需要进行随机的一次性更改,我不介意留下一些基本的实用程序。
有些人可能认为一个问题是,即使您删除了未使用的 CSS,您可能也需要发送更多 HTML。 举个例子,我使用 Tailwind 的一个小项目有一个组件,它使用了一个 77 个字符的类,并且该组件在一个页面中重复了 24 次,因此它会累积到生成的 HTML 中。 较大的项目可能具有比这一个重复次数更多的组件。
如果使用客户端渲染,这不是问题,因为这些类在组件中只定义一次。在其他情况下,使用 Tailwind 的
@apply
将多个使用的类减少为一个类可能会有帮助。但是,我认为这不是什么大问题:HTML 总是会被压缩的。Gzip 很棒,Brotli 效果奇佳。如果你没有使用任何这些,那你就搞砸了。
我认为它非常好,但正如作者所说,仅适用于具有 HMR 的环境和以 JS 为中心的环境,因为使用这种方法时,抽象一组样式(即实用程序类)的唯一方法是创建一个 js 组件。没有多个文件扩展名。没有中间库。你想要抽象?为此创建一个 js 文件。我认为这是一个非常简洁的“关注点分离”。
感谢您解决了这个问题。虽然对于基本的示例,抽象很少,但是当您使用媒体查询等内容时,您会用到更多。例如,要使网格在屏幕尺寸超过指定的大断点时具有五列,在 Tailwind 中只需
这包括媒体查询和所有内容。相比之下,该 CSS 为
CSS 长得多,而且您甚至无法使用内联样式进行媒体查询。但是,我尊重关注点分离,尽管使用 Tailwind 的 @apply,仍然可以利用使响应式设计变得简单的抽象。
纯 CSS 方法绝对可以压缩。首先,那里不需要
minmax()
函数。其次,您可以将repeat
数字抽象为变量,因此在初始设置后,设置其他列布局将非常简洁。我认为更具说明性的比较/示例应该是这样的
对比
(当然假设使用 Sass,但也可以不用。)
虽然纯 CSS 方法显然不那么简洁,但它也为您提供了更大的灵活性(例如,如果您不希望所有列都具有相同的大小),并且设置所需的更多“精确性”有助于我更好地理解它,并且感觉更自由。
我完全同意您关于“实用程序类框架就像保龄球护栏一样用于样式”的评估。事实上,我更喜欢那样。
这关乎使用一致的模式和构建块进行设计。
一个论点是关于 DRY 的。出于这个原因,您完全可以在 css 类中使用 @import 语句。
实用程序类非常适合实用程序样式。它们不太适合其他样式。这里的所有内容都是真实的和公平的。但这也是组合分层问题。如果您必须使用相同的 15 个低级实用程序类来重新组合重复的内容,那么事情就会变得难以管理。
我对“实用程序类”(说实话:我尝试过的只有 Tailwind)的两个主要问题都与性能有关。
首先,当然,CSS 更小——通常小得多——但这需要付出文件大小膨胀的代价(所有这些类名确实加起来)。当然,我们可能谈论的是一个(正确修剪的)CSS 文件,它比(A)BEM 或 SMACSS 等“正常”编码风格小数百 KB,而 HTML 则“仅仅”大几 KB。但是,在第一次访问站点后,浏览器会缓存哪一个?没错:CSS。
我遇到的另一个问题是,随着 HTTP/2、服务器推送和模块化组件的兴起,拥有全合一的 CSS 文件正在走向灭亡。相反,CSS 的未来在于多个较小的 CSS 文件,每个文件都专门调整和定制以设置站点的单个组件的样式。现在,这种方法并不排除仍然使用 Tailwind(等),但它确实使其变得适得其反:而不是在一个全合一的 CSS 文件中有一个
.top-0 { top: 0; }
规则,您可能会在每个单独的 CSS 中都有一个类似的规则。将其乘以可能在多个组件中使用的众多实用程序类,最终结果是毫无理由的巨大、不必要的膨胀。我不明白 css-in-js 的必要性。从 2016 年起我就停止使用 Atomic CSS-html 了。
关注点分离
丑陋且难以阅读的 Html
更难实现响应式
CSS 通过模块和变量提供了答案。因此,使用 Atomic 或 Tailwind 是过度工程。
保持 KISS 原则,使用更少的库,更少的框架。CSS 框架不会对你有多大帮助。
我有点吹捧 Tailwind,但现在在实际尝试将其用于实际的生产应用程序后,不得不说我有点后悔。
非常长的类名,更不用说你根本不知道应该如何以有意义的方式排序这些类。
像样式变体这样的东西在 Tailwind 上实际上要困难得多,你最终会得到这些类连接助手,这对我来说有点奇怪。
我有一个想法,即你有一个特殊的 CSs 语法用于一组原子类,然后你可以将其应用于元素,有点不同于 @apply 提取样式的地方。
我看到的优势是你可以轻松地组织各个类,它还可以让你组合这些组。
它也可能有助于组合变体,但我必须在实践中才能看到。
公平地说,它仍然是一个很棒的工具,用于原型设计。我经常访问 Tailwind Play 来为某些组件和想法制作原型。
Svelte 值得一看。
它获取组件的< style >块中声明的任何样式。
然后在构建时预渲染,然后写入使用该组件的任何页面上的< head >中。
这是一个超级棒的框架,我将在我的下一个宠物项目中使用它。
https://svelte.net.cn
因为我同意批评任何事物都必须站在公平立场的论点,所以我必须抓住这个机会,将这一原则应用于 Tailwind 用户对 CSS 的批评。
他们的辩论一方也经常出现恶意论点、比较和稻草人谬误。
例如
“系统”值减少了魔法数字”并非仅对 Tailwind 成立。同样的方法完全可以与 CSS 一起使用,而且只需付出最少的努力。
“浏览器中的响应式设计”也是如此。本身并非 Tailwind 的优势。
“内联样式减少了命名”同样也不是 Tailwind 的真正优势。只有在与 BEM 或 OOCSS 等教条式方法进行比较时才会如此。掌握了特异性和级联工作原理,绝对可以利用这些特性来最大程度地减少命名需求。只有在
:where()
出现后才更真实。在纯 CSS 中,唯一真正需要想出的名称是您的模块的名称。就像 Tailwind 一样。Tailwind 支持者为了证明其使用合理性而提供的 CSS 示例通常构建得很糟糕,选择不当或规则集意图错误。
以下选择器通常用作 CSS 问题的示例
这里的问题是,它实际上是一段构建得很糟糕、非常糟糕的 CSS 选择。但你一开始就不应该创建这些糟糕的选择器!好消息是你不需要这样做。可以也应该开发出更好、更清晰、更智能的 CSS。这不是 CSS 的问题,而是你(以及可能你的同事)编写 CSS 的方式的问题。
我无法摆脱一种感觉,即在许多方面,Tailwind 和类似的东西被用来解决 Tailwind 用户自己造成的问题。通过正确地运用 CSS 的强大功能,许多支持 Tailwind 的论点都会瓦解。结合原子 CSS 范式的真正问题(而非本文中提到的不公平问题),编写智能、有目的和明确的 CSS 的原生和自然方式可以也应该被认为是原子框架和教条式方法的更轻量级和更简单的替代方案。
或者,作为一个社区,我们可以继续通过增加复杂性、依赖项和膨胀来解决我们自己创造的问题来重新实现对误解的设计语言的原生功能。我认为我们应该尝试在尝试避免它之前,智能地使用 Web 平台提供的设计语言。
不清楚为什么您认为该 CSS 选择器示例构建得很糟糕。
构建得很糟糕,因为它选择了
div
和a
作为不必要的中间标签。如果您想设置h2
和img
标签的样式,请直接选择它们,而无需中间标签。只有当这些中间标签的存在改变了样式需求时,它们才应该是选择器的一部分。我敢打赌,它们的存在不会改变任何东西,因此应该将它们排除在外。
阿门。
我不知道也不在乎有多少开发人员同意这一点:编写强大、经过深思熟虑的 CSS 代码是一种需要数年才能真正掌握的艺术形式。
从头开始手动编写样式指南可以让你获得知识和能力,让你能够自信地导入、捆绑、连接和以逻辑方式注入你的样式。
从那时起,您可以将所有布局、辅助工具、实用程序等编译成一个丑陋的、压缩的和缓存的主 CSS 文件。
加载一次,它处理除与一次性相关的唯一样式之外的所有内容
组件。
加载单个文件可能听起来令人生畏且过时,但手动编写优秀的 CSS 本质上是轻量级的。
恢复静态网站!
思考的素材
嗯,很有意思。:3
我实际上在使用 Tailwind,而且很少回头。如果你习惯了类名和系统,它运行得非常好。
别误会我的意思,我喜欢编写原生 CSS,也使用过 SCSS,并以 BEM 作为概念工作了几年。但是 Tailwind 坚持了下来。它在基于组件的系统中运行得更好。它消除了我在使用 BEM 时遇到的痛点。命名事物,经常在 HTML/PHP 和 CSS/SCSS 之间切换。
我们应该问自己的问题是:我们的样式必须与 HTML 紧密耦合吗?HTML 非常语义化,但是 CSS 是否必须仅仅复制它?我无法确定,这只是一些我思考的事情。
目前我遇到的 Tailwind 的一个痛点是它的膨胀。对于新用户和不知道如何控制输出大小或清除未用样式的人来说,它看起来确实很大。并且为像 IE11 这样的旧浏览器提供一个后备选项将是很棒的。只是说说而已。 :)
我喜欢这个例子。我不喜欢在 2010 年看到它——所以,我不确定为什么我们要在 2021 年加倍投入。
现在,“左对齐”不是真的,而且对于我试图让我为我工作的初级开发人员来说,它真的没有帮助。
我认为每个人都是出于好意。我在聚会上遇到了一些人在前端非常高效,而对 CSS 的了解非常有限,所以,这些东西很受欢迎是有原因的。
我在我的 CSS-tricks 文章中稍微谈到了实用程序类如何类似于你使用 mixin 的方式(但也并非如此):“关于类型模式和样式指南”。你对此有什么想法?
内联样式无法做到的一件事是响应式设计,Tailwind 具有响应式类,你可以在你的样式类之前使用它们来根据大小更改元素的外观,例如
text-lg md:text-xl
。悬停也是一样,我敢肯定你无法使用内联样式来实现。在使用 BEM、SMACSS、语义类名等十年后,我尝试了 Tailwind,我再也不想使用其他任何东西了。在大型代码库中避免意外后果变得容易得多。
虽然这对于 0 来说是正确的,但我不知道我是否以同样的方式看待 0。
-0
类对我来说更像是“移除”,而 0 恰好是移除距离的基线。其他数字都不严格地与自身对齐,而是与 rem 单位的比例对齐。例如,对于填充类 p-2 来说,它不对应于 2rem,而是 0.5rem。这些数字是从需要为每个大小想出词语中抽象出来的,当大小比小、中、大更复杂时,而
-0
恰好对应于 0rem。