样式组件 vs. CSS 样式表

2025-05-27

样式组件 vs. CSS 样式表

在过去的几年中,CSS-in-JS 解决方案已在前端领域变得流行,其中包括许多产品,例如styled-componentsemotion,它们提供了一种将组件和样式定义放在一起的方法。

这些库的强大之处在于能够使用 JavaScript 功能来增强可重用性并轻松创建超越视觉呈现的设计系统。

对于这篇文章,我们将styled-components特别关注它是如何改变人们设计 React 组件的方式的。

虽然使用“CSS-in-JS”解决方案有很多优势,但在前端开发者中,它自然是一个颇具争议的话题。我将列出它styled-components与更“传统”的 CSS 样式表相比的一些主要优缺点,这些优点和缺点影响了我日常的 React 编程方式。

样式化组件

优点

没有全局范围的选择器

在我看来,使用 的最显著的好处之一styled-components是不再需要担心选择器名称存在于具有级联覆盖的全局范围内。

一致性

UI 库在前端开发中非常流行。它们可以让你快速上手,但通常需要你覆盖作者编写的 CSS 选择器,才能自定义样式以匹配你的设计。

当使用 CSS 框架时,这可能会产生不必要的学习曲线,或者至少,你会发现自己不断地来回切换,以在 CSS 的海洋中找到你试图覆盖的选择器的正确名称。

styled-components让您可以轻松地将组件发布到 NPM,并确保它不仅可以通过 props 和/或通过扩展为用户提供超级可定制性,styled(Component)而且由于选择器冲突的可能性为零,它的外观和行为始终与本地一样。

开箱即用的 Sass 语法

在您的styled-components定义中,您可以开箱即用地使用SASS语法,而无需设置任何预处理器和额外的构建工具。

在样式定义中,您可以使用&字符来定位当前组件,然后从那里,您可以定位父元素、子元素或同级元素以及添加伪选择器。

请参阅下面的要点,了解一些快速示例,您可以利用此语法根据组件周围的元素更改组件的样式:

const List = styled.div`
// Target immediate children of List that have siblings
& > * + * {
margin-top: 16px;
}
// Target any List components that are the child of an <article>
article & {
color: white;
}
// Target any adjacent Lists
& + & {
margin-top: 16px;
}
// Target the List when hovered
&:hover {
background-color: red;
}
`;

主题

使用 Reacts Context API,您可以传递styled-components一个ThemeContext主题对象,使其可以在任何组件中访问,并且默认情况下可以插入到您的styled定义中。

我经常使用主题来存储颜色、间距大小以及一些实用函数,这些函数可以操作颜色、生成阴影和贝塞尔曲线等等。在创建可复用的设计系统方面,一切尽在掌握。主题化可以让你轻松地从 Sketch 文件中提取所有原始值和颜色,并将所有组件保持在同一个页面上。

提示text:我发现,对于颜色,使用更通用的名称(例如、primary& )会更有帮助,accent这样名称就不会特定于颜色值本身。通过更通用的名称,您可以创建具有相同键名的多个主题(例如“暗黑模式”),这样您就可以随时切换它们,而无需更改组件树中任何样式定义。

这里有一个快速要点,其中包含有关如何在 中访问主题的示例styled-components

动态造型

如上所示,您可以以与访问主题相同的方式访问传递给组件的任何道具,从而为创建可重用、可定制的组件提供强大的机会。

样式按钮就是一个例子。按钮可能具有多种尺寸、颜色变化和其他样式差异,具体取决于它们在页面上的显示位置。但是,不同样式之间的标记和逻辑可能完全相同。

您无需在无疑是庞大的 CSS 文件中创建多个类定义,而是可以利用 props 以一种让熟悉 React 的人感觉自然的方式动态地更改样式。

我个人使用此功能的一种方法是创建一个可重复使用的排版组件,我可以在整个应用程序中使用该组件,而无需创建多个样式定义。

提示:请参阅下面的要点,了解使用该 prop 的示例as。此 prop 是一个相对较新的功能,styled-components它进一步扩展了上述概念。我们还将 prop 中的颜色名称传递给主题,这样我们就可以使用自己的配色方案,而无需扩展样式定义。

缺点

学习曲线

大多数(即使不是全部)前端开发人员都对 CSS 有所了解,这styled-components需要你以不同于传统 CSS 的思维方式进行思考。幸运的是,一旦你习惯了样式和组件的共存,学习曲线就会相对较短。

此外,所有styled-components更“高级”的功能都是可选的,并且您可以毫无问题地使用普通的旧 CSS - 尽管对于并非都认同 CSS-in-JS 的开发团队来说,这通常是一个不必要的障碍。

与传统 CSS 的集成可能会很痛苦

无论
您使用的是 MaterialUI 之类的工具,还是您现有的样式表,将styled-components它们集成在一起可能会使查找和调试样式变得困难。CSS 文件和样式定义在代码库中通常彼此相距甚远(在 CSS 框架的情况下甚至很大程度上无法访问),并且您无法查看哪些 CSS 定义与哪些 CSS 定义相关,styled-components以及样式如何级联覆盖。

可能是一种“时尚”

与 CSS 本身相比,CSS-in-JS 是一个非常年轻的概念,并且很可能像它出现一样迅速消失。

技术总是会过时或“不再流行”,有时会持续一段时间,有时则只是短暂的炒作。

这对开发者来说可能很令人沮丧——尤其是当“下一个大型库”出现时,这意味着你不得不重构甚至完全重写你的样式。这一点也更加凸显了这一点——正如那句老话所说:“如果它没坏,就不要去修理它。”

我认为可以公平地说,CSS 和更成熟的框架和预处理器(如 SASS)还远未被破坏。

表现

在较大的应用程序和网站中,资产的性能和缓存对于维持稳定的用户体验至关重要,尤其是在连接速度较慢的地区,技术变得更容易获得。

styled-components在构建时将所有样式定义解析为纯 CSS,并将它们全部放入<style>index.html 文件头部的标签中。

这里的问题是,即使您使用 Gatsby 和 React 之类的工具静态生成您的网站,不仅 HTML 文件的大小会增加,而且也无法对输出 CSS 进行分块。

此外,类名本身也是动态生成的,本质上会破坏缓存,因为在构建/渲染之间事情可能会发生变化。

提示:稍微缓解此问题的一种方法是在您的应用程序中使用代码拆分(查看react-loadableReact Code Splitting) - 因为styled-components发生在 JS 领域,代码拆分确保仅将当前页面所需的样式和 javascript 发送到浏览器,其余部分可以在用户导航时延迟获取。

共置可能会使你的组件膨胀

无论以何种方式设置 DOM 样式,并非所有内容都能作为可应用于多个元素的可重用组件。

通常,样式规则可以特定于一个永远不会重复使用的元素,styled-components具体来说,可能有一个组件被导入然后在不同的文件中多次扩展,从而创建比必要更多的代码。

当然,将代码抽象到components文件夹中的自己的文件中是没有意义的,因此最明显的位置是与其父组件位于同一源文件中。

这是我所看到的一种常见模式styled-components,,通常,组件源代码的前 100/200 行是一大堆样式化的组件定义。

CSS样式表

优点

不固执己见、普遍适用

CSS 是通用的,并且对您如何呈现 UI 没有任何意见,这使得它非常适合拥有遗留 CSS 并正在迁移到新框架或重建其网站或产品的团队。

例如,您可以轻松地在 React 项目和 Vue 项目中使用相同的样式表,这在使用不同语言编写的网站和 Web 应用程序之间共享样式时尤其有用。即使您使用预处理器,它最终也会编译为 CSS,并且仍然可以通用。

缓存和性能

标准 CSS 文件易于浏览器优化,可在本地缓存文件以供重复访问,最终提升性能。虽然这可能意味着更多的网络请求,但就实际文件大小而言,CSS 文件通常较小。

快速迭代新设计

您可以非常轻松地删除整个样式表并创建一个新的样式表来刷新应用程序的外观和感觉,而无需挖掘数百个组件。

您还可以将样式表拆分成特定的文件,以实现一定的模块化。例如,为网格系统和设计元素创建单独的文件,这样您就可以保留布局,但完全改变外观。

然而,styled-components如果操作正确,您可以通过主题获得相同的结果,并获得更轻松、更清晰的开发人员体验。

易于使用

团队选择使用 CSS 的另一个原因styled-components是,对于经验丰富的开发人员来说,理解原生 CSS 要容易得多styled-components。另一方面,对于熟悉 CSS 但从未使用过的开发人员来说styled-components,这可能会让他们感到困惑,并且在他们克服学习曲线并弄清楚如何浏览项目源代码的过程中,会浪费不必要的时间。

框架

对于新开发人员来说,CSS 框架是了解事物工作原理的好方法,同时为您提供实现您的想法所需的基础。

对于styled-componentsJavaScript 经验很少甚至没有的人来说,理解代码会很困难。

即使是没有 React 或styled-components经验的经验丰富的 JS 开发人员,一旦遇到诸如插入条件样式的 props 之类的功能,也可能需要停下来思考一下。

缺点

可读性

任何曾经使用传统 CSS 构建过完整应用程序或网站的人都知道,样式表很快就会变得长得难以理解且难以浏览。

如果您在几个月的多个这种规模的项目之间工作,来回切换并尝试理解这些文件至少会很乏味。

这样做的唯一可能的好处是可以完全解决覆盖的非常明显的规则styled-components- 一旦人们开始使用更细粒度的选择器div > p,然后强制他们的样式与之一起工作,!important.就几乎不可能维护。

旧版 CSS 可以继续使用多年

通常这些庞大的样式表文件变得如此复杂和冗长,以至于清理旧的、过时的或未使用的样式就像大海捞针,虽然这只会让事情变得更糟,但开发人员可以创建一个新的样式定义并覆盖这些样式。

全球范围和特异性

CSS 中的全局作用域意味着每个唯一的样式定义都必须具有唯一的选择器名称。此外,由于 CSS 文件的级联特性,您很容易对某些内容无法正常工作或样式相互更改感到困惑。

这通常需要严格的命名约定和注释,以确保在添加、删除旧代码和查找文件时所有内容都是准确的并且以可靠的方式工作。

没有真正的动态造型

如果我们想用纯 CSS 有条件地改变元素的样式,即使使用 React 这样的框架,也可能需要编写大量不必要的代码才能完成。

我们需要定位一个具有我们想要动态设置样式的类的 DOM 元素,为样式更改创建另一个类,通常添加一些事件监听器,然后有条件地从元素中添加或删除新类。

平心而论,React 通过事件回调、状态、道具和组件重新渲染使其中一些操作变得更容易,但与替代方案相比styled-components,它可以为您节省大量时间和代码。

保持一致性

拥有一个主题styled-components对于确保您的风格在整个过程中保持一致且易于修改大有帮助。

虽然原生 CSS 支持变量,允许用户在样式表中定义类似的可复用值,但其语法很烦人,而且会使 CSS 文件臃肿,你需要在文件中四处查找才能记住正确的变量名。同样,这个问题通常可以通过一套规范的命名约定和结构来解决,至少整个团队都需要了解这些约定和结构。

总结

总的来说,作为一名每天编写 React 的工程师,我觉得它styled-components是几乎每个项目的必备依赖项,并且一旦你开始转变对样式的思考方式,从纯粹让事物符合设计到创建可重用、可组合和可适应的样式定义,它就会成为一种非常强大的工具,不仅可以受益于 React 所钟爱的模块化和易用性,还可以共同形成一个完整的设计系统,可以从一个事实来源与应用程序的其余部分一起适应。

原生 CSS 可能永远不会消失,至少短期内不会。但是,如果你花费大量时间使用 React 从设计文件创建 UI 视图——而且你styled-components还没有尝试过,我强烈推荐你使用它。

我很想听听你对 Styled Components 的看法,你用过吗?你是 Stylesheet 的铁杆粉丝吗?我们来聊聊吧!

免责声明:我在Stream工作。我们提供 Feeds 和 Chat API,为超过 5 亿终端用户提供数字体验,并且我们在许多应用程序、SDK 和组件库中混合使用样式组件和样式表。如果您有兴趣了解这些内容,我建议您查看我们的Stream Chat React Components ,您也可以在这里了解更多关于我们出色的聊天产品的信息

快乐造型✌️

文章来源:https://dev.to/nickparsons/styled-components-vs-css-stylesheets-5cho
PREV
使用 husky、lint-staged、prettier 和 stylelint 设置 git precommit hook 开始使用
NEXT
🚀 使用 JavaScript 检测用户是否在线/离线