- 原文:Atomic CSS-in-JS
- 时间:2020/04/27
- 做者:Sébastien Lorber
- 译者:ziven27
- 翻译时间:2020/05/10
译者: 国内你们都去搞 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
你们可能据说过各类 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 代码库中也获得了承认,但这个现存的“关注点分离”的主流思是相违背的。
由于咱们使用简单的类选择器,因此“关注点分离”也再也不是什么大的问题。
咱们如今经过结构来修改样式,会有如下几个特色:
固然这会增大 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,并制定好命规则。 但这很难确保它的易用性,以及控制它的膨胀率。 这个可以在让多我的使用的状况下保持一致吗? 是否受bus factor因素影响?
译者注: bus factor 我猜想是指的代码里面的破窗效应。
Tailwind 的方法很是方便,能够解决其中的一些问题。
它并无真正为全部网站提供惟一的 utility CSS 文件。相反,它仅提供共享的做用域和命名约定。经过配置文件,您能够生成属于本身的utility CSS。
Tailwind的知识能够移植到其余应用程序,即便它们没有使用彻底相同的类名。这让我想起了React的“学习一次,随处写”的哲学。
我见过有人提到说,Tailwind 的类,几乎能知足了他们平常 90% 或 95% 的样式需求。这个覆盖面已经足够大了,咱们一般不须要使用一次性样式。
基于这个点您可能会想知道为何要用 Atomic CSS 来替代 Tailwind 呢?
在严格遵照 Atomic CSS 中一个 Class 只有一条规则的逻辑下你会获得什么?您最终将得到更大的 HTML 标记,和不方便的命名约定?无论怎么样,Tailwind 已经内置了许多原子类。
所以,咱们应该放弃 Atomic CSS 的想法,而选择看起来更简单的 Tailwind ?
Tailwind 是一个很是棒的解决方案,可是仍然存在一些还没有解决的问题:
与 Tailwind 相比,手写 Atomic CSS 样式并非一个好的方案。
CSS-in-JS, and utility/atomic CSS 仍是有不少共同点的。两种方法都主张从标记中进行样式化,相似写内联样式,这使它们具备许多类似的属性(例如,能够放心地移动内容)。
Christopher Chedeau 极大地帮助了在 React 生态系统中传播 CSS-in-JS 的想法。 在屡次talks中,他解释了CSS的问题:
Utility/atomic CSS CSS-in-JS / atomic CSS 解决了其中的一些问题,但显然不是所有(特别是样式的不肯定性解析)。
若是它们具备如此多的类似性,咱们不能同时使用它们吗?
Atomic CSS-in-JS 能够看做是 “自动化的 atomic CSS”:
我不知道目前全部 CSS-in-JS 库对于 Atomic css 的支持状况。 支持它其实是 CSS-in-JS 库的实现细节。支持状况多是有的有,有的没有,或者是可选项。
我将重点推荐如下两个解决方案,这致使最近出现了两个大规模的原子CSS-in-JS 的使用:
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 是在 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给到的具体数字:
这两个库彷佛有一个类似且至关简单的API,可是很难说,由于咱们对 Stylex了解很少。
值得强调的是,React-Native-Web 会处理 CSS 缩写 和 margin: 0;
这样的语法。
让咱们看看 Twitter 上的 HTML 是什么样的:
再看看新的 Facebook:
不少人看到这个可能会吓一跳,但不得不认可它确实有效,并且仍然可使用。
在 Chrome 检查器中浏览样式可能有点困难,但 devtools 能够帮助:
和手写 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 命名约定,就能够很是快速地编写 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 项目中使用。
另外再推荐一个本身多年 Atomic CSS 使用下来的经验总结的一个 npm 库。
名称 | NPM | github |
---|---|---|
@_nu/css-acss |
![]() |
![]() |
能够把@_nu/css-acss
理解为阉割版的 Tailwind。用阉割来换取上手成本和使用体验。五分钟看完文档你就能理解全部的逻辑。
我的能力和翻译水平有限,有错误欢迎指正