css-in-JS 库为我们提供了一种编写 CSS 的新方法。他们旨在解决 CSS 的局限性,例如缺乏动态功能、范围和可移植性。尽管 CSS-in-JS 有其优势,但它是一项有争议的技术,因为许多开发人员询问是否值得进一步复杂化前端开发。
本文旨在为您提供 CSS-in-JS 库的高级概述。我们将研究这些库是如何工作的,它们解决了哪些问题,以及如何决定是否应该使用它们。
什么是 CSS-in-JS?
自从基于组件的 javascript 框架出现在前端开发中以来,CSS-in-JS 库一直受到关注。angular、react、vue 和其他框架都基于称为“组件”的模块,您可以从中构建整个单页应用程序 (SPA)。组件通常是 UI 元素,例如按钮、弹出窗口或导航栏。您只需要创建一次组件,就可以在应用程序的任何上下文中重用它。
但是,您应该如何有效地设置 SPA 组件的样式?如果您使用全局 CSS 文件,那么很难判断最终结果会是什么样子。由于 CSS(级联样式表)的级联特性,样式表可以按任何顺序加载并以任何组合相互覆盖。当涉及到 SPA 样式时,管理依赖项是另一个问题。如果在使用常规网站时依赖管理很困难,那么使用超过一定复杂性的模块化 Web 应用程序几乎是不可能的。
一个设计良好的 CSS-in-JS 库可以解决所有这些问题。实际上,CSS-in-JS 是一个 JavaScript 库,它将每个 javaScript 组件与其所有所属的 CSS 规则和依赖项捆绑在一起。因此,组件可以独立运行,无需依赖任何外部 CSS 文件。这就是Styled Components库的共同创建者 Max Stoiber 在他出色的 博客文章中 解释 CSS-in-JS 库是如何工作的:
“三年来,我在没有任何 .css 文件的情况下设计了我的 Web 应用程序。相反,我用 JavaScript 编写了所有的 CSS。...我可以添加、更改和删除 CSS 而不会产生任何意想不到的后果。我对组件样式的更改不会影响其他任何内容。如果我删除一个组件,我也会删除它的 CSS。不再有仅附加的样式表!” – 马克斯·斯托伊伯
我认为这个陈述很好地总结了这项技术。使用 CSS-in-JS 库,您可以在 .js文件中编写所有 CSS,以便它们可以作为 JavaScript 模块工作。
CSS-in-JS 库示例
尽管每个 CSS-in-JS 库都有相同的用途(即用 CSS 捆绑组件),但每个库的功能和语法略有不同。让我们看看最流行的 CSS-in-JS 库是如何相互叠加的。
特定于框架的与与框架无关的
一些库仅适用于特定的 JavaScript 框架。例如, Radium 是为 React 应用程序创建的,而Styled jsx 仅支持用 JSX编写的组件 (您可以在有和没有 React 的情况下使用)。
特定于框架的 CSS-in-JS 库使用与其支持的框架相同的语法。例如,Styled JSX 使用 JSX 语法中的模板文字将 CSS 样式添加到组件。以下代码(来自Styled JSX 的 GitHub 文档)创建了两种类型的按钮,一种是常规的,一种是大的:
const Button = (props) => (
<button className={ 'large' in props && 'large' }>
{ props.children }
<style jsx>{`
button {
padding: 20px;
background: #eee;
color: #999
}
.large {
padding: 50px
}
`}</style>
</button>
)
/* Creates a regular button */
<Button>Hi</Button>
/* Creates a large button */
<Button large>Big</Button>
其他 CSS-in-JS 库,例如JSS、Emotion和前面提到的样式化组件与框架无关。因此,您可以将它们与任何基于组件的框架、纯 JavaScript 一起使用,其中一些(例如 Aphrodite )也 可以与 Web 组件一起使用。
要查看与框架无关的 CSS-in-JS 库在现实生活中的外观,您可以尝试 JSS 的在线游乐场 或查看Aphrodite 的 GitHub 文档中的以下 Web 组件示例:
/* Registers a Web Component with red background */
import { StyleSheet, css } from 'aphrodite';
const styles = StyleSheet.create({
red: {
backgroundColor: 'red'
}
});
class App extends htmlElement {
attachedcallback() {
this.innerHTML = `
<div class="${css(styles.red)}">
This is red.
</div>
`;
}
}
document.registerElement('my-app', App);
唯一选择器与内联样式
为了处理范围,大多数 CSS-in-JS 库(例如 JSS、Emotion 和 Styled Components)会自动为每个组件生成一个唯一的选择器。要亲自查看,您可以访问 Styled Component 的主页并使用浏览器的开发人员工具检查其中一个示例。例如,我"I'm a styled <Button />"使用 Firefox DevTools 检查了粉红色的幽灵按钮:
如您所见,Styled Components 生成了两个独特的类,一个调用 components__SecondButton-sc-1gmolv7-3 fWxBIM按钮,另一个调用 components__AlignCenter-sc-1gmolv7-0 hjdyfl父 div。
虽然这是创建绝对唯一的选择器的好方法,不会导致任何 CSS 特异性问题,但源代码看起来并不漂亮。或者,一些 CSS-in-JS 库(例如 Radium)将内联 CSS 动态添加到 HTML,而不是生成唯一的类。
后一种方法不仅使 HTML 代码更具可读性,而且还具有其他优势,例如更好的性能、源顺序独立性和死代码消除。然而,使用内联样式也有一些缺点。根据镭的文档:
“尽管如此,有一些常见的 CSS 特性和技术是内联样式不容易适应的:媒体查询、浏览器状态(:hover、:focus、:active)和修饰符(不再是 .btn-primary!)。Radium 提供了一个标准接口和抽象来处理这些问题。”
所以,这就是权衡。根据您的需求,您可以决定哪种方法更适合您。
独特的功能
CSS-in-JS 库不仅在语法、框架支持和范围处理方面有所不同,而且每个库都具有其他库中不一定包含的独特功能,例如:
尽管大多数库都带有良好的文档,但这里有一个 Michele Bertoli 的比较表,其中包含多个 CSS-in-JS 库的最重要特性。
CSS-in-JS 的优点
现在,让我们谈谈 CSS-in-JS 库的优点(尽管我已经提到了其中的一些)。
本地范围
默认情况下,CSS 不允许本地范围。每个样式规则都有一个全局范围,因此它适用于整个项目。结果,样式可以以令人惊讶的方式相互覆盖。前端开发人员创建了多种方法来为 CSS 添加模块化,例如 BEM、OOCSS 和 SmacSS。预处理器和 postCSS 是模块化 CSS 的另一种方式。CSS-in-JS 库通过自动作用域将这个概念提升到一个新的水平,从而实现高水平的可预测性。
封装
封装的组件隐藏了实现的细节。它们只向外界公开一个 api,以便其他组件可以与它们交互。封装有助于维护并消除错误,因为您可以在同一个地方修改所有与组件相关的代码,而不必担心意外更改应用程序的其他部分。
可移植性
由于组件包含正确运行所需的所有源代码、样式和逻辑,因此您可以安全地移动它们。它们基本上是开箱即用的,让您可以创建松散耦合的应用程序,其中组件仅通过 API 相互通信。
可重用性
组件是可重用的,因此您只需编写一次,然后就可以在任何地方运行它们。您不仅可以在同一个应用程序中重用组件,还可以在使用相同框架构建的其他应用程序中重用组件。
动态功能
由于 CSS-in-JS 本质上是 JavaScript 代码,因此您可以将复杂的逻辑应用于样式规则,例如循环、条件、变量、基于状态的样式等。因此,如果您需要创建需要动态功能的复杂 UI,它是一个理想的解决方案。
CSS-in-JS 的缺点
尽管 CSS-in-JS 库允许您以合乎逻辑且有效的方式构建基于组件的应用程序,但它们也具有一些可能使您对它们保持警惕的特性。
学习曲线
CSS-in-JS 肯定有一个学习曲线,特别是如果您以前既没有使用过基于组件的框架也没有使用过 Web 组件。除了学习新语法之外,您还需要学习一种新的思维方式,这需要时间并且可能会在一段时间内减慢您的开发工作流程。
额外的复杂层
使用 CSS-in-JS 库会为您的前端堆栈添加一个额外的层,这有时可能是不必要的。尽管 CSS-in-JS 很好地管理了复杂性,但并不总是值得麻烦,尤其是在一个更简单的项目的情况下。
代码可读性
自动生成的选择器会显着降低代码的可读性。如果您经常使用浏览器的开发人员工具进行调试,这对您来说可能是一个巨大的问题,但对于初学者来说也是如此,因为他们必须理解他们编写的代码。
那么,什么时候应该使用 CSS-in-JS 库?
CSS-in-JS 库为您提供了一种简单且安全的方法来设置基于组件的应用程序的样式。除了 JavaScript 框架,您还可以将它们与 Web 组件一起使用。如果您想为单一前端创建复杂的用户体验,例如基于状态的功能,它们也可以派上用场。
另一方面,如果您是初学者,想要创建没有动态前端的网站,或者喜欢简单性和代码可读性,那么 CSS-in-JS 可能不适合您。您可能会合理地发现您的首选工具(例如 Sass 或 PostCSS)非常适合您的目标,并且您不想仅仅为了新奇而选择新技术。
- 特定于框架的与与框架无关的
- 唯一选择器与内联样式
- 独特的功能
- 本地范围
- 封装
- 可移植性
- 可重用性
- 动态功能
- 学习曲线
- 额外的复杂层
- 代码可读性