驯服CSS-in-JS这头野兽 2021-11-06 默认分类 暂无评论 2115 次阅读 ![taming-css-hero.png][1] CSS-in-JS非常棒。当它逐渐受到重视的时候,我还记得使用它是多么的自由--在那个自定义属性还没有广泛使用的时代,它允许我们在JavaScript中创造丰富的动态体验!更棒的是,从NPM中消费一个组件库,而不需要愚蠢的bundler配置,这已经成为现实。更棒的是,从NPM消费一个组件库,而不需要繁琐的捆绑器配置,这已经成为现实,只要导入就可以了 在Atlassian工作期间,我有幸参与了Atlassian设计系统的工作,该系统在很大程度上依靠CSS-in-JS来编写样式。在这段时间里,我看到了用styled-components和情感定义的组件,用字符串和对象定义的样式,以及你不会立即想到的代价,如性能问题,理解样式声明的困难,以及进化的停滞。 如果我们能够改变我们编写样式的方式来改善这些方面,而不需要跳到另一个库中去,会怎么样呢? **彩虹的颜色** --------- CSS-in-JS的好处之一是它非常灵活,然而这也是它最大的缺点之一。我们今天编写的体验是非常动态的,不同的外观、状态和尺寸,都有一些不同的实现方式。我见过的一种常见的方式是使用条件性对象展开的组合样式[或者更糟糕的if语句],但是给定一个足够大的道具集,你就有可能出现组合爆炸的风险 考虑到随着时间的推移,一个组件可能会经历多个工程师,甚至是团队!这就是很多潜在的错误。这是一个很大的潜在误解。 让我们玩一玩,看看这在实践中是什么样子的,按一下按钮,增加更多的道具。 ``` const styles = (isDisabled, isBold) => { return { borderRadius: 3, color: 'black', backgroundColor: 'lightgrey', ...isBold && { color: 'lightgrey', backgroundColor: 'black', }, ...isDisabled && { color: 'lightgrey', backgroundColor: 'gray', }, }; }; function Lozenge({ children, isDisabled, isBold }) { return {children}; } ``` 无论是作为人类还是静态分析工具,要理解这个声明是越来越复杂了! 从一个函数中建立和返回的样式以及通过参数的间接性使得输入和使用之间的联系充其量是模糊的。要理解一个组件的当前状态在一组特定的输入下可能是什么,可能会很混乱。 **从无限中拉回来** ----------- 随着代码库的增长,我发现自己想把所有的细枝末节都自动化,并努力实现代码的一致性这一神圣的目标。然而,有趣的是,如果你看了上面的代码,就会发现,没有明确的样式声明和复杂的样式组合的调用站点,就很难,几乎不可能成功地在规模上对自创的样式进行润色和进化。 如果我们能想出一个写出最好的CSS(在JS中)的目标清单,它们会是什么?我的清单包括 - 清晰的调用站点 - 类型化的声明 - 容易被工程师扫描和理解 - 鼓励静态声明的样式 - 样式的一种方式 为了实现这些,我们可以设置一些约束。我列出的约束条件最终是 - 使用CSS道具 - 使用JS对象 - 样式必须在顶层范围内声明 - 样式不能被导入/导出 - 样式不能被嵌套 - 样式不能组合在一起[在它们自己的声明中]。 你的样式会是什么样子的?玩一玩,看看当我们对上面的例子中的样式进行约束时是什么样子的。 ``` const styles = css({ borderRadius: 3, color: 'black', backgroundColor: 'lightgrey', }); function Lozenge({ children }) { return {children} ``` 如果你和我有同样的感觉,你会注意到这个的输出与你使用CSS模块的方式非常相似 简单的一口大小的样式声明,在拥有的组件中被组合在一起。总的代码行数可能会增加,但我们获得的连接和流程分析却弥补了这一点。 **捆绑在一起** --------- 强加约束与代码中更好的结果相关,即使它不是很明显。让我们通过几个例子来看看,由于我们所应用的约束条件,有什么改进。 **性能** ------ 让我们从围绕性能的更有趣的方面开始。这些约束条件意味着在服务器上渲染时生成的样式更少!这意味着在服务器上生成的样式更少。当样式不能被提前知道时,例如当所有的用户都有自己的图片时,这种情况就更严重了。请注意,每个独特的头像都有一个样式声明,而在应用约束条件时只有一个。 玩一玩,看看当我们约束样式的时候是什么样子的。 ``` ``` 让真正的动态样式流经样式道具是我们应该保留在我们的工具箱中的东西,而这些约束条件真的让我们使用它。静态样式流经CSS道具,动态样式流经样式道具,而我们在服务器上生成的样式更少?对我来说,这听起来很不错。 **代码分析** -------- 想象一下前面描述的情况,即样式的定义没有明确的调用站点,并使用嵌套的条件休息对象和if语句,然后还想象一下试图为此写一个lint规则,让我告诉你,这可不是一件容易的事 这些约束条件非常棒,因为你可以为这些样式应该如何编写写一些非常强大的规则。顺序,不允许的样式,强制的颜色使用,甚至通过控制它们如何通过CSS道具动态地应用。没有什么是不可以的。 ``` const focusRing = { boxShadow: '0 0 0 2px blue', }; ``` 用这些约束条件编写的样式声明是清晰和简单的,事实上是如此简单,以至于可以详尽地对其进行静态分析。 代码演进 当你写的代码很容易被静态分析的时候,一个合乎逻辑的下一步就是你可以[大规模]地改变它。使用编译时间的CSS-in-JS解决方案越来越受欢迎,所以如果你的目标是最小化你的应用程序,你肯定要考虑使用它们。假设我们是。 因为我们知道静态样式[CSS道具]和动态样式[内联样式]流动的底线[最坏情况]是什么,我们完全可以控制。 这里有一个例子,将情感代码转换为使用一个叫做vanilla-extract的库。 ``` import { css } from '@emotion/react'; const styles = css({ outline: 0, border: 0, backgroundColor: 'blue', }); const disabledStyles = css({ opacity: 0.5, backgroundColor: 'gray', }); function StyledComponent({ isDisabled }) { return ; } ``` ``` import { style } from '@vanilla-extract/css'; export const styles = style({ outline: 0, border: 0, backgroundColor: 'blue', }); export const disabledStyles = style({ opacity: 0.5, backgroundColor: 'gray', }); ``` **不仅仅是造型设计** ------------ 希望你能像我第一次开始思考这个问题时一样,觉得这本书很有趣。找到适用于我们所写的代码的约束条件,不仅仅适用于我们的体验的风格化。 下次当你深入到你的代码库中时,想想如果你在写状态管理、组件、定义API、甚至是出货时的功能上应用更多的约束条件,会有什么机会出现。你会对这些可能性感到惊讶的。 [1]: http://guobacai.com/usr/uploads/2021/11/623062555.png 标签: javascript, css, styled-components
评论已关闭