[译] Atomic CSS-in-js

译者: 国内你们都去搞 JS 去了,能够看到咱们有能够与 REACT 抗衡的 VUE。却显见有相似 CSS-in-js, OOCSS,BEM,Atomic CSS ... 的 CSS 解决方案出现?这是为何呢?css

随着 Facebook 和 Twitter 最近的产品技术方案的迭代更新,咱们看到了一个新的流行趋势: Atomic CSS-in-JS。vue

在这篇文章中,咱们将看到什么是原子CSS,它是如何与像 TailwindCSS 这样的 functional / utility-first CSS 之类技术方案的关系,以及哪些基于 react 框架的大厂是如何使用它的。react

由于我不是这方面的专家,因此不要期望深刻了解它的优缺点。我只是但愿你能从对它的了解中有所启发。git

注意: Atomic CSS 与 Atomic Design 设计无关。github

译者注:Atomic CSS 是 CSS 代码的一种设计模式,Atomic Design 是对于设计资源和设计组织方式的一种设计理念。web

什么是 atomic CSS?

你们可能据说过各类 CSS 解决方案,例如BEM,OOCSS ...npm

<button class="button button--state-danger">
    Danger button
</button>
复制代码

现在,人们愈来愈喜欢像 Tailwind CSS 同样的 utility-first 概念。 这与 Functional CSS 和 Tachyon 很接近。react-native

<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
  Button
</button>
复制代码

使用一组实用程序类的样式表,咱们其实能够作得更多。设计模式

Atomic CSS 能够看做是 utility-first CSS 的一种极致抽象: 全部的 CSS 类都有且只有一个单一的,独特的 CSS 规则。Thierry Koblentz (Yahoo!) 在 2013年 的“ Challenging CSS Best Practices” 首次提到了 CSS。缓存

/* Atomic CSS */
.bw-2x {
  border-width: 2px;
}
.bss {
  border-style: solid;
}
.sans {
  font-style: sans-serif;
}
.p-1x {
  padding: 10px;
}
/* Not atomic, because the class contains 2 rules */
.p-1x-sans {
  padding: 10px;
  font-style: sans-serif;
}
复制代码

咱们不得不认可在使用 utility/atomic CSS 时,是将结构层和样式层耦合在了一块儿:当咱们须要更改按钮颜色时,咱们修改的是 HTML,而不是 CSS。 这种紧密耦合的方式在现代 CSS-in-JS React 代码库中也获得了承认,但这个现存的“关注点分离”的主流思是相违背的。

由于咱们使用简单的类选择器,因此“关注点分离”也再也不是什么大的问题。

咱们如今经过结构来修改样式,会有如下几个特色:

  1. 随着咱们添加新功能,样式表的膨胀率反而会减少
  2. 咱们在移动 HTML 的时候就能同时修改咱们的样式。
  3. 咱们在删除一个组件的同时,就能确保咱们删除了与之相关的样式。

固然这会增大 HTML 的体积。对于服务器渲染的 Web 应用程序,可能会是一个问题,可是利用 gzip 能够很好地压缩类名中的高冗余度,这和压缩 CSS 文件中重复 CSS 样式的方式同样。

你不须要在任何状况下都使用 utility/atomic CSS , 它更适合大多数通用的样式素材。

译者注:也就是 Design Token,Atomic CSS 在对接 Design Token 会发挥出它最大的优点

一旦定义好 utility/atomic CSS,它就很难改变或增加。 利用这个特性,咱们就能够主动将它缓存(例如,把它添加到 vendor.css 中,并不须要每次都从新部署)。 它移植行也很是高,能够很方便的在其余应用程序中使用。

utility/atomic CSS 的局限性

Utility/atomic CSS 很是的棒, 可是它也有一些坑。

一般咱们会在项目初期手动建立 utility/atomic CSS,并制定好命规则。 但这很难确保它的易用性,以及控制它的膨胀率。 这个可以在让多我的使用的状况下保持一致吗? 是否受bus factor因素影响?

译者注: bus factor 我猜想是指的代码里面的破窗效应。

让 Tailwind 来拯救咱们

Tailwind 的方法很是方便,能够解决其中的一些问题。

它并无真正为全部网站提供惟一的 utility CSS 文件。相反,它仅提供共享的做用域和命名约定。经过配置文件,您能够生成属于本身的utility CSS。

Tailwind的知识能够移植到其余应用程序,即便它们没有使用彻底相同的类名。这让我想起了React的“学习一次,随处写”的哲学。

我见过有人提到说,Tailwind 的类,几乎能知足了他们平常 90% 或 95% 的样式需求。这个覆盖面已经足够大了,咱们一般不须要使用一次性样式。

基于这个点您可能会想知道为何要用 Atomic CSS 来替代 Tailwind 呢?

在严格遵照 Atomic CSS 中一个 Class 只有一条规则的逻辑下你会获得什么?您最终将得到更大的 HTML 标记,和不方便的命名约定?无论怎么样,Tailwind 已经内置了许多原子类。

所以,咱们应该放弃 Atomic CSS 的想法,而选择看起来更简单的 Tailwind ?

Tailwind 是一个很是棒的解决方案,可是仍然存在一些还没有解决的问题:

  • 须要学习有针对性的命名约定
  • CSS规则插入顺序仍然很重要
  • 能够轻松删除未使用的规则吗?
  • 咱们如何处理其他的一次性样式?

与 Tailwind 相比,手写 Atomic CSS 样式并非一个好的方案。

和 CSS-in-JS 作比较

CSS-in-JS, and utility/atomic CSS 仍是有不少共同点的。两种方法都主张从标记中进行样式化,相似写内联样式,这使它们具备许多类似的属性(例如,能够放心地移动内容)。

Christopher Chedeau 极大地帮助了在 React 生态系统中传播 CSS-in-JS 的想法。 在屡次talks中,他解释了CSS的问题:

Problems with CSS at Scale

Utility/atomic CSS CSS-in-JS / atomic CSS 解决了其中的一些问题,但显然不是所有(特别是样式的不肯定性解析)。

若是它们具备如此多的类似性,咱们不能同时使用它们吗?

走进 Atomic CSS-in-JS

Atomic CSS-in-JS 能够看做是 “自动化的 atomic CSS”:

  • 您无需再建立 CSS 类名
  • 普通样式和一次性样式的处理方式相同
  • 可以提取页面的关键 CSS ,并进行代码拆分
  • 有机会解决 JS 中 CSS 规则插入顺序的问题

我不知道目前全部 CSS-in-JS 库对于 Atomic css 的支持状况。 支持它其实是 CSS-in-JS 库的实现细节。支持状况多是有的有,有的没有,或者是可选项。

我将重点推荐如下两个解决方案,这致使最近出现了两个大规模的原子CSS-in-JS 的使用:

一样的还有: Styletron, Fela, cxs

React-Native-Web

React-Native-Web 是一个很是有趣的库:它容许在 Web 上渲染 React-Native。 这里咱们并非真正在谈论跨平台的 移动/ Web开发(请从论坛以获取更多详细信息)。

做为一名Web开发人员,你只须要了解 React-Native-Web 是一个常规的 CSS-in-JS 库,带有一小部分原始的 React 组件。 不管您在何处看到 View,均可以将它替换为div,这是您的最佳选择。

React-Native-Web 由 Nicolas Gallagher 建立,致力于 Twitter 移动端。 他们逐步将其部署到移动设备上,不肯定确切时间,但可能在 2017/2018 年左右。 从那时起,它已被其余公司(大联盟足球,Flipkart,Uber,泰晤士河…)使用,但最重要的部署是 Paul Armstrong 领导的团队开发的新的 2019 Twitter 桌面应用程序。

Stylex

Stylex 是在 Facebook 上开发的新 CSS-in-JS 库,用于 2020 年 Facebook 重写(当前为beta)。 看来他们计划有朝一日将其开源,可能使用不一样的名称。

值得一提的是,React-Native-Web 的做者 Nicolas Gallagher 是 2 年前被 Facebook 聘用的。 看到它的某些概念被 Facebook 重用也就不足为奇了。

与 React-Native-Web 不一样,Stylex 彷佛并不专一于跨平台开发。

我收到的全部信息都来自论坛 :) 咱们将不得不等待更多详细信息。

膨胀率

正如 Atomic CSS 所指望的那样,Twitter 和 Facebook 的 CSS 都已经大幅减小了,他们都遵循图中的曲线。 虽然仍是须要为一些应用付出努力。

Facebook给到的具体数字:

  • 他们的旧网站只是着陆页就有 413Kb 的CSS
  • 他们的新站点整个站点为 74Kb,包括黑暗模式

资源和输出

这两个库彷佛有一个类似且至关简单的API,可是很难说,由于咱们对 Stylex了解很少。

值得强调的是,React-Native-Web 会处理 CSS 缩写 和 margin: 0;这样的语法。

生产环境

让咱们看看 Twitter 上的 HTML 是什么样的:

再看看新的 Facebook:

不少人看到这个可能会吓一跳,但不得不认可它确实有效,并且仍然可使用。

在 Chrome 检查器中浏览样式可能有点困难,但 devtools 能够帮助:

CSS rules 执行顺序

和手写 utility/atomic CSS 不同的是,JS 库可以使样式不依赖于 CSS 规则的插入顺序。咱们都知道,在规则冲突的状况下,获胜的不是 class 属性的最后一个类,而是在样式表中最后插入的规则。 咱们只能经过使用简单的基于类的选择器来解决特异性问题。

实际上,这些库避免在同一元素上输出具备冲突规则的类。 他们确保标记中声明的最后一个样式始终获胜。 “覆盖的类”已被过滤,甚至没有进入 DOM。

const styles = pseudoLib.create({
  red: {color: "red"},
  blue: {color: "blue"},
});
// That div only will have a single atomic class (not 2!), for the blue color
<div style={[styles.red, styles.blue]}>
  Always blue!
</div>
// That div only will have a single atomic class (not 2!), for the red color
<div style={[styles.blue, styles.red]}>
  Always red!
</div>
复制代码

若是一个类有多个规则,而其中只有一个被覆盖,则 CSS-in-JS 库将没法过滤该类而不删除非覆盖的规则。

若是一个 class 有一条简单的缩写规则,例如 margin:0,可是覆盖它的样式是 marginTop:10,会遇到一样的问题。 若是 margin:0 的简写语法被扩展为 4 个不一样的类(marginTop:0;marginLeft:0; marginRight:0; marginBottom:0),这些库就可以过滤出不该出如今 DOM 中被覆盖的类。

你仍是喜欢 Tailwind?

一旦了解了全部 Tailwind 命名约定,就能够很是快速地编写 UI。就很难再回到相似 CSS-in-JS 那样手工一行行去写样式的方式。

Nothing prevents you for building your own abstractions on top of an atomic CSS-in-JS framework. Styled-system might be able to run some of the CSS-in-JS libraries supporting atomic CSS. It’s even possible to reuse naming conventions for Tailwind in JS, if you feel you are productive with it.

没有什么能够阻止你在Atomic CSS-in-JS 框架之上构建本身的抽象。 Styled-system可让不少 CSS-in-JS 的库支持 Atomic CSS。若是你仍是更喜欢 Tailwind 的方式,你甚至能够改写 Tailwind 在 JS 中的命名规则。

这是传统 Tailwind 的写法:

<div className="absolute inset-0 p-4 bg-blue-500" />
复制代码

咱们随便找一个方案(react-native-web-tailwindcss) 我在goole 上看到的。

import {t} from 'react-native-tailwindcss';
<View style={[t.absolute, t.inset0, t.p4, t.bgBlue500]} /> 复制代码

就生产率而言,这并无太大不一样。 并且您可使用 TypeScript 规避一些输入错误的问题。

总结

关于Atomic CSS-in-JS,我想说的就这些。

我从未在任何大型生产环境项目中使用过Atoatomic CSS, atomic CSS-in-JS 或着 Tailwind 。 我可能在某些地方错了,请随时在Twitter上纠正我。

我认为原子CSS-in-JS在React生态系统中是一种趋势,我但愿您从这篇文章中学到了有用的东西。

因为我尚未找到任何关于原子CSS-in-JS的文章,因此这篇文章主要是为我本身写的。当我在之后的博客文章中提到原子CSS-in-JS时,我但愿有一个资源连接(我计划撰写更多关于React-Native-Web和跨平台的文章,敬请关注)。

感谢您的阅读。

译者的话

Atomic CSS 我不知道已经推荐了多少次了,这么说吧它是目前现存的方案中,能解决 CSS 难题最多的解决方案没有之一。特别是在基于组件化思惟的react 或者 vue 项目中使用。

  1. 我说 CSS 类名能够缩写,你不要打我!
  2. 如何管理 CSS “内裤”
  3. 「CSS思惟」组件化VS原子化

另外再推荐一个本身多年 Atomic CSS 使用下来的经验总结的一个 npm 库。

名称 NPM github
@_nu/css-acss
npm package
github

能够把@_nu/css-acss 理解为阉割版的 Tailwind。用阉割来换取上手成本使用体验。五分钟看完文档你就能理解全部的逻辑。

我的能力和翻译水平有限,有错误欢迎指正

相关文章
相关标签/搜索