Robin Weser 的 “原子 CSS 中的简写-长写问题”,是一段关于棘手问题的有趣旅程。重点是,当您承担将类似 HTML 和 CSS 的东西转换为实际的 HTML 和 CSS 的任务时,您将不得不自行解决一些边缘情况,即使您能解决的话。在本例中,Fela(我们 刚提过)将 CSS 转换为“原子”类,但是当您将简写和长写混合在一起时,生成的类与级联一起使用会导致错误。
我认为这种产生原子 CSS 的 CSS-in-JS 的整体理念非常有趣,所以让我们快速退一步看看它。
原子 CSS 表示 **一个类 = 一个任务**
比如这样
.mb-8 {
margin-bottom: 2rem;
}
现在想象一下,有 *数千* 个这样的类可以使用,并且几乎可以做任何 CSS 可以做的事情。
为什么要这样做?
以下是一些原因
- 如果您完全采用这种理念,这意味着您将发布更少的 CSS,因为没有重复的属性/值对,并且没有为作者编写原因而创建的类名。我猜想一个全原子样式表(根据使用情况进行修剪,我们稍后会讨论)的大小是手写样式表的四分之一,甚至更小。发布更少的 CSS 意义重大,因为 CSS 是一个阻塞资源。
- 您可以避免命名事物。
- 如果您限制可用的类,您将获得一定程度的“免费”设计一致性。
- 有些人只是更喜欢它,并说它使他们更快。
如何获取原子 CSS?
没有什么能阻止您自己动手。这就是 GitHub 使用 Primer 和 Facebook 所做的事情(在 FB5 中,*不代表您应该效仿大型企业!*)。他们决定了一组实用程序样式,并将其作为包发布(主要发布给自己)。
也许整个理念的起源是 Tachyons,它只是一堆巨大的、有主见的类,您可以直接获取并使用。
但大多数情况下…
Tailwind 是主要玩家。
Tailwind 有很多不错的默认设置,但它除了是一组原子样式之外,还做了一些非常聪明的事情
- 它可配置。您可以告诉它您希望所有这些类做什么。
- 它鼓励您“清除”未使用的类。您确实需要正确地执行这部分,因为如果您不这样做,您将无法真正获得原子 CSS 的好处。
- 它有一个 UI 库,因此您可以立即开始使用它。
等等,我们不是在讨论自动生成的原子 CSS 吗?
哦,对了。
值得一提的是,雅虎也是 早期参与者。他们的主要想法是,您实际上将使用函数作为类名(例如 class="P(20px)"
),并在构建步骤中将其处理为类(在 HTML 和 CSS 中)。我不确定它有多流行,但您可以看到它与 Tailwind + PurgeCSS 并没有太大区别。
**如今,您不必 *编写* 原子 CSS 来 *获取* 原子 CSS。**来自 Robin 的文章
它使我们能够以熟悉的“单片”方式编写样式,但获得原子 CSS。这提高了可重用性,并减小了最终的 CSS 包大小。每个属性-值对只渲染一次,即在第一次出现时。从那时起,每次我们再次使用该特定对时,我们都可以从缓存中重复使用相同的类名。一些执行此操作的库有
• Fela
• Styletron
• React Native Web
• Otion
• StyleSheet坦率地说,我认为这是实际使用原子 CSS 的唯一合理方法,因为它不会影响编写样式时的开发体验。我 **不** 建议手动编写原子 CSS。
Johan Holmerin 在 CSS-Tricks 上 写了关于 style9 的文章,它也做同样的事情。
我认为这很酷。我尝试过多次直接编写原子 CSS,但我就是不喜欢它。谁知道为什么。我一生中学习了很多新东西,但这个就是没有引起我的共鸣。**但我绝对喜欢计算机为提高生产环境中的 Web 性能而执行的任何操作。**如果构建步骤将我编写的 CSS 转换为原子 CSS... 那太棒了。上面有五个库可以做到这一点,因此这个概念肯定有其意义。
这些方法基于 CSS-in-JS 是有道理的,因为它们绝对需要处理标记和 CSS - 因此这是最有意义的上下文。
你们怎么看?
在 twind 中,一个运行在 js 中的 tailwind,我们遇到了同样的问题。为了以确定性顺序插入 CSS 规则,我们为每个 CSS 规则计算一个优先级编号,该编号决定样式表中的位置(升序;例如,较低的数字排在前面)。该理念源于 otion,我们针对 tailwind 对其进行了调整。我们基本上使用以下规则(我省略了一些特定于 tailwind 的规则)
暗模式 - 覆盖亮模式样式
媒体查询 - 使用
min-width
值以移动优先方式排序其他 at 规则 - 比如
prefers-reduced-motion
伪类 - 确保正确的顺序;例如,
active
覆盖focus
和hover
(参见 :hover、:focus 和 :active 伪类何时生效?)声明数量(降序) - 这使得单声明样式可以覆盖多声明样式
属性的最高优先级(忽略供应商前缀和自定义属性) - 简写属性首先插入,例如,长写属性覆盖简写属性
我目前使用 Tailwind、Vuetify 和 Bulma。我很难理解它的附加价值。style = “background: red” 与 class = “red” 有什么区别?我发现 HTML 变得非常臃肿。
我们也在这样做,感觉很棒。
我不同意您关于原子 CSS 值得的任何理由。让我们逐条分析
没错,您的 CSS 更少了,但您的 HTML 中将有数百/数千个更多的类,这些类也是阻塞的,因此它只是将负载从一个资源传递到另一个资源。
如果您使用其中一个库,那么没错。但即使使用传统的演示库(Bootstrap/Foundation)也是如此。一旦您想扩展它,您可能需要比以前命名更多的东西(虽然名称更简单,当然)。
理论上是的,因为每种 CSS 属性都有一个类。但开发人员更有可能在 HTML 元素上添加一堆不一致的类?不一致性又一次简单地转移到了 HTML 中。
好吧,我们不能反驳这一点。
最终,我们应该使用我们习惯使用的(虽然我们通过反复使用变得习惯),产生优秀作品的(虽然这取决于我们使用工具的熟练程度),以及实用的(取决于预算/环境)。
重复的词语,比如类名,压缩得很好,所以这不是问题。
是的,有时你可能想要创建一个“组件”,即一组可重用的样式,但正如你巧妙地预测的那样,你可能在命名它方面会遇到更少的麻烦。
我认为“一致性”这个词指的是间距尺度、颜色等。在编写 CSS 时,除了代码审查者和一定程度的代码 linting 工具之外,没有什么可以阻止你违反这些规则。在实用优先的 CSS 中,这是不可能的,所以我会说更强的一致性是固有的。
实用优先的 CSS 乍一看确实很糟糕,因此需要一些情感投资。Chris 不喜欢它,我喜欢它,因为我无法找到适合我的 CSS 最佳实践组合,所以 Tailwind 的方法引起了我的共鸣。其他人继续讨厌它,这完全取决于动机。
我想我对 Tailwind 最大的痛苦是,当我开始装饰一个 HTML 片段,添加 15 个类,复制它,然后不得不改变该长行(或列表)中的某个类属性。
它很难解析。
当许多元素带有那么多的类时,这并不会使它们更容易阅读。
当然,人们可以取这些类名列表并创建一个唯一的类,我认为我更喜欢这种方法,但我太习惯于 Bootstrap 和它们的 Sass 实用程序类了,所以就用它们的方式吧。
最后,我可以理解为什么它很有吸引力,人们似乎很享受它。
在 twind 中,我们引入了分组来减少类列表的大小。你的例子可以写成
此外,我们支持这些组件类别的别名
我始终不明白的是,使用原子 CSS,几乎总是需要更多的工作才能进行小的视觉更改,因为你最终会一遍又一遍地重复相同的概念样式集。因此,与其在一个地方说每个(例如)卡片应该是什么样的,然后从那里进行专业化,不如说你最终会搜索每个看起来有点像卡片的实例。这还没有谈论到原子 CSS 的包大小有多大(由于 HTML 和 CSS 的增加)。坦率地说,唯一的优势似乎是它允许初始开发更容易,这对于模型来说是可以的……但为什么不直接使用内联样式标签呢?坦率地说,我乐于使用各种 CSS 解决方案,从作用域 CSS 到样式组件,再到语义 CSS……除了原子 CSS 之外,所有这些都非常合理。
我认为原子 CSS 适合基于组件的框架,比如 Vue、React 或 Svelte。我总是使用 Tailwind 在 React 或 Svelte 项目中,它非常强大,完全没有重复,所有样式都由组件重用。但对于原生 HTML,我认为原生 CSS 更好。
我一直在开发 Compiled,这是一个构建时原子 CSS-in-JS 库,位于:https://github.com/atlassian-labs/compiled
它旨在与其他库具有功能奇偶性,并且能够完全提取到一个静态原子样式表中。以及保持 DX 就像今天一样。你甚至不会觉得它是作为原子 CSS 输出的!
有趣的是,原子 CSS 除了重用和一致性之外还有其他优势。
它使我们能够实现运行时有效的样式组合,并使用构建时样式。
它非常强大,并且确实能够实现更大的生态系统潜力,因为你可以在 NPM 上发布软件包,并且仍然可以灵活地覆盖样式,无需担心级联。它只是工作。
非常期待接下来会发生什么!
这篇文章中最大的缺失(也是让许多评论者烦恼的地方)是提取组件的概念。TailwindCSS 在这里对此进行了很好的解释:https://tailwind.org.cn/docs/extracting-components
我认为这是 Tailwind 最大的优势之一。能够继续使用 BEM 等方法,但仍然保持原子系统的一些优势。你可以创建自己的“两全其美”方法。
我刚刚开始定期使用 Tailwind,在 11ty、Preact 和 WP 模板中使用它。到目前为止,我喜欢它的灵活性。
真实故事
15 年前,当我刚开始做开发时,我的 CSS 开始朝这个方向发展。我用 w25 表示
width: 25%
,用 w50 表示width: 50%
,还有十到十五个表示宽度、高度、边距、填充……几个月后,我意识到自己为 CSS 编写 HTML 是多么愚蠢,而不是反过来。我停了下来,开始编写真正的 CSS,再也没有回头。
现在,10 到 15 年后,我坐在门廊上,看到年轻一代犯下了我当年犯下的同样的愚蠢错误。
只是大多数人似乎没有意识到错误,就让它像我当年那样。
这很令人难过。
这篇文章很有趣,以前不知道双选择器解决方案。
我写了一篇非常相似但更一般的关于原子 CSS-in-JS 的文章
https://sebastienlorber.com/atomic-css-in-js
这项技术已应用于新的 Facebook 网站,现在 CSS 随着线性扩展而变得更小。
预渲染的静态页面可以具有非常小的内联 CSS,即使 HTML 增大,也能更快地加载。
对我来说,仍然存在一个问题,因为它也使 JSX 代码更大,导致框架水合需要下载更多的 JS 代码。目前还不确定如何解决这个问题。
原子 CSS 和内联样式之间有什么区别?一个抽象层,在 99% 的情况下永远不会被用作抽象?
将样式推送到更可缓存的内容。
acss.io 上的常见问题解答回答了这个问题。
原子 CSS 与使用内联样式有什么区别?
嗨,Chris,
你提到(关于 ACSS)
这篇文章是关于“自动生成的原子 CSS”,我很惊讶你没有提到动态库比静态库的巨大优势:它们能够生成作者需要或想要的任何样式。换句话说,作者不必从样式表中有限的样式列表中进行选择,他们可以动态创建样式!
这正是大多数人忽略的一点!
我一直无法让 Tailwind/PurgeCSS 根据我的静态网站的 DIST 文件夹删除未使用的样式。我希望能够在创作时使用原子类,构建,然后根据我的内容作者实际使用的内容删除未使用的原子类。有没有人找到方法来做到这一点?
我认为“原子 CSS”运动完全是误入歧途,愚蠢至极。作为用户,你是否曾经尝试过自定义(或修复)使用原子 CSS 的网站的元素?你无法做到。
基本上,这只是对设计页面元素并为它们合理命名的责任的一种懒惰的放弃。