CSS-in-JS 还是传统 CSS?现代样式方案的选择指南

红黑树下乘凉
2025-06-30 10:08
阅读 591

开篇:为什么我会关心这个“小问题”?

开篇:为什么我会关心这个“小问题”?

作为一名前端开发者,我每天都在跟样式打交道。从最初的 index.css 到后来的 SCSS、Less,再到现在的 CSS-in-JS,样式的写法可以说是层出不穷。然而,无论技术如何演变,有一件事情从未改变:样式管理一直是前端工程中最容易失控的部分之一。

这篇文章不是为了告诉大家哪种方式“更好”,而是想通过我在几个真实项目中的经历,分享在不同场景下我们该如何选择适合自己的样式方案,并谈谈我个人的一些思考和建议。


问题描述:样式混乱、冲突频繁

问题描述:样式混乱、冲突频繁

几年前我接手了一个中大型 React 项目,是一个内部使用的 CRM 系统。整个项目已经开发了近两年,技术栈是 React + Redux + Material-UI。项目初期采用的是传统的全局 CSS 文件(.css.scss),但随着功能模块越来越多、参与开发的团队也逐渐扩大,样式的问题开始频繁暴露出来:

  • 类名冲突严重:比如不同的页面都用了 .btn,但各自定义的 margin、padding、hover 效果却不一致。
  • 难以维护:修改某一部分样式时,常常需要在多个文件之间反复查找。
  • 复用性差:一些组件样式无法很好地抽离复用,每次都要复制粘贴再调整。

最让我印象深刻的是一次 QA 报告:“点击用户卡片时按钮的颜色变深,但在订单页又恢复正常”。排查半天才发现是因为两个组件使用了同一个 class 名,却分别定义在两个 .scss 文件里,而打包后优先级覆盖了。

那一刻我意识到,传统的 CSS 写法虽然简单直接,但在中大型项目中确实存在很多隐患。我们需要一个更好的解决方案来应对这些问题。


解决方案一:尝试 CSS-in-JS(以 styled-components 为例)

为了解决上述问题,我们决定在新开发的模块中引入 CSS-in-JS 方案。首选的是当时流行的 styled-components

1. 引入过程

我们并没有马上在整个项目中全面替换,而是先在一个新功能模块中试点 —— 用户行为分析面板(数据可视化组件较多)。

安装依赖非常简单:

npm install styled-components

然后我们就开始用它来写组件样式:

import styled from 'styled-components';

const Card = styled.div`
  background: #fff;
  border-radius: 8px;
  padding: 16px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
`;

const Title = styled.h3`
  color: #333;
`;

function UserCard({ user }) {
  return (
    <Card>
      <Title>{user.name}</Title>
    </Card>
  );
}

这种写法最大的好处就是:样式作用域天然隔离,不需要担心 class 名冲突。而且由于每个组件的样式紧贴其结构逻辑,阅读代码也更直观了。

2. 小插曲:首次上线的样式抖动

不过刚上线的时候我们发现了一个问题:页面加载过程中会出现短暂的“无样式状态”(FOUC),特别是在低网速的环境中。这是因为 styled-components 默认会在运行时注入样式到 <head> 中,而不是像 CSS 文件那样在构建时生成。

解决方法也很简单:

  • 使用服务器端渲染(SSR) + styled-componentsServerStyleSheet
  • 或者在客户端项目中配合 Webpack 配置开启提取 CSS 插件(例如 mini-css-extract-plugin)。

但说实话,在非 SSR 的纯前端项目中,CSS-in-JS 对性能还是有一定影响的,尤其是在组件数量庞大的情况下,可能会导致 JS 包体积增大、首屏加载变慢。

3. 更大的收益:提升协作效率

最让我惊喜的是团队协作层面的提升。当多个小组并行开发时,大家再也不需要商量 class 名该怎么命名、也不用互相检查是否会有冲突了。每个人的组件样式都是局部有效的,出了问题只查自己的文件就行。


解决方案二:回到传统 CSS(这次用了 BEM + Tailwind)

前端性能优化图表-1

不久之后,公司另一个项目启动:一个面向用户的高并发商城网站前端。虽然同样是 React 项目,但我们这次选择了不一样的路线。

这次我们决定继续使用传统的 CSS,但换成了两种工具结合的方式:

  • BEM 命名规范:用于自定义组件的样式组织;
  • Tailwind CSS:用于快速搭建页面布局和通用 UI 元素。

为什么会做这样的选择?

因为我们对性能要求非常高。商城首页需要秒开、交互流畅,而我们评估后认为使用 CSS-in-JS 可能会增加不必要的 JS 执行负担。同时,设计师已经提供了统一的视觉规范文档,这意味着我们可以更灵活地使用 Tailwind 这样的原子化 CSS 框架。

1. Tailwind 的体验

Tailwind 提供了一种完全不同的写法:不再定义 class 类名,而是直接在 HTML 标签上写样式:

<div className="flex items-center justify-between p-4 bg-white shadow-md rounded-lg">
  <span className="text-gray-700 font-medium">商品名称</span>
  <button className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
    加入购物车
  </button>
</div>

这种方式一开始有点不适应,尤其对于习惯了语义化 class 的人来说会觉得代码“太碎”。但当你用习惯以后,你会发现:

  • 不需要再频繁切换到 .css 文件去定义新 class;
  • 样式调试更快捷,因为可以直接看 HTML 上的 class;
  • 可以借助编辑器的智能补全,快速写出想要的效果。

2. BEM 的辅助作用

我们在定制组件(如轮播图、价格对比卡片等)时采用了 BEM 规范,确保结构清晰、命名统一。

比如一个轮播图组件:

<div class="carousel">
  <div class="carousel__item carousel__item--active">...</div>
  <div class="carousel__item">...</div>
</div>

对应的 CSS 文件则可以精确控制每一个子元素的状态,避免样式扩散。


效果总结:各有千秋,取决于项目特性

经过这两个项目的实践,我得出了一些经验性的结论:

特性/方案 CSS-in-JS(styled-components) 传统 CSS(BEM + Tailwind)
样式封装性 极好,组件级作用域 需要规范管理
开发效率 快,代码内联 快,尤其是 Tailwind
可维护性 易定位问题 依赖良好的命名规范
性能表现 稍逊色(JS 注入样式) 更优(提前编译好的 CSS)
学习成本 相对较高(需理解动态注入机制) 较低,标准 CSS + Tailwind 的上手较快
调试难度 Chrome DevTools 支持良好 同样支持良好

对于我们那个 CRM 系统,CSS-in-JS 成功缓解了样式冲突和多人协作问题;而对于那个高流量的商城项目,Tailwind + BEM 的组合带来了更高的性能表现和更高效的页面搭建速度。


经验分享:我的几点建议

结合我这几年踩过的坑和实际经验,给正在纠结样式的你几点建议:

1. 选型前先问自己这几个问题:

  • 项目类型是什么?是企业内部后台系统、还是高流量的 C 端网站?
  • 团队人员构成如何?是新人多,还是资深工程师主导?
  • 是否关注首屏性能?是否需要 SEO 支持?
  • 有没有设计规范和 UI 库?是否已有统一的设计语言?

这些都会直接影响最终的技术选型。

2. 别被框架绑架

无论是 styled-components 还是 emotion,或是 Tailwind、Bootstrap,它们都是工具。关键是看它能否帮你更好地完成任务。

有时候我们会过于追求新技术、新潮流,反而忽略了解决问题的本质。

举个真实的例子:有一次我在一个小团队里推广 Tailwind,结果组员反馈“感觉像回到了 inline-style 的年代,很难读”。那我们就果断回归了传统的 SCSS 分离写法,并加强了命名规范的培训。

3. 性能永远值得留意

不管用什么方案,记得关注构建输出大小、加载顺序以及样式树的复杂度。即使是 Tailwind,如果不清除未使用的 CSS,最终打包出来的 CSS 文件也会非常庞大。

可以用 PostCSS 插件 + PurgeCSS 来清理冗余样式:

// postcss.config.js
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
    purgecss: {
      content: ['./src/**/*.html', './src/**/*.js'],
    },
  },
};

4. 调试技巧和工具推荐

Chrome DevTools 在样式调试方面做得非常不错,尤其是:

  • 右键点击元素 → “Inspect Element”
  • 查看 computed style 查看最终样式值
  • 使用快捷键 CMD/Ctrl + Shift + M 切换设备视图进行响应式调试

另外,VSCode 推荐安装以下插件:

  • vscode-styled-components(CSS-in-JS 支持)
  • Tailwind CSS IntelliSense(自动补全 Tailwind class)

5. 实践建议:从小处着手,逐步演进

如果你现在正维护一个老项目,或者不想冒然改掉所有样式写法,不妨采取渐进式策略:

  • 新增组件使用新的样式方案
  • 已有组件按需重构
  • 搭建组件库或设计系统统一风格

这样既不会引发项目动荡,也能让团队慢慢接受变化。


结尾:样式没有银弹,只有合适与不合适

回过头来看,这些年我们尝试过各种方式来写样式 —— 从最初的纯 CSS 到后来的预处理器、CSS Modules,再到如今流行的 CSS-in-JS 和 Tailwind,每一种都有它的优势和适用场景。

作为开发者,我们要做的不是一味追随某种流行方案,而是要根据当前项目的实际情况、团队能力和长远目标,做出最适合当下环境的选择。

技术服务于产品,工具服务于团队。

希望这篇文章能帮你在面对“CSS-in-JS vs 传统 CSS”这个问题时,少一点迷茫,多一份从容。

如果还有疑问或者你也有一些实践经验想聊聊,欢迎在评论区留言交流~ 🚀

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝