CSS-in-JS vs 传统CSS:现代样式方案选择指南

区块链先锋
2026-01-15 16:09
阅读 617

——一个裸辞半年的前大厂程序员的深夜复盘

作者注:我是小陈,去年十月从阿里 P6 岗位裸辞,坐标杭州,刚在临平买了个 89 平的小两居,月供 6200。Gap 半年,简历投了 83 家公司,面试 17 轮,上周五终于签了 offer(月薪从 15k 涨到 22k)。今天不聊跳槽,聊聊我在准备面试时反复被问到的一个问题:“你们项目用的是 CSS-in-JS 还是传统 CSS?为什么?”


一、那个让我失眠的夜晚

时间倒回到上个月 12 号晚上,凌晨两点。窗外下着雨,我坐在电脑前,老婆已经睡了,房贷账单还摊在桌上。明天要面一家做 SaaS 工具的创业公司,终面技术负责人说:“我们前端栈比较新,你得对样式方案有深度理解。”

我翻出自己写过的一堆 React 组件库,突然意识到一个问题:我用了三年 Styled Components,却从来没认真想过“为什么”要用它

更可怕的是,面试官如果问我:“如果让你从零搭建一个中后台系统,你会选哪种样式方案?” 我的答案会不会显得很菜?

那一夜,我泡了杯速溶咖啡(别笑,裸辞后真不敢点瑞幸了),打开了 GitHub、Stack Overflow 和一堆 Medium 文章。这一查,才发现自己掉进了一个巨大的认知陷阱。


二、CSS-in-JS:大厂的“高级玩具”

在阿里的时候,我们团队几乎清一色用 Emotion(后来迁移到 vanilla-extract)。理由很“政治正确”:组件化、作用域隔离、动态主题、TypeScript 支持好

记得有一次和隔壁 Java 后端老张吃饭,他吐槽我们前端:“你们天天换框架,连写个颜色都要 import 一个变量,是不是太卷了?”

我当时还嘴硬:“这叫工程化!你们 Java 不也搞 Spring Cloud Config 管配置?CSS 也是配置的一种啊!”

但说实话,在业务压力大的时候,CSS-in-JS 的优势反而成了负担

举个真实例子:去年 Q3,运营同学紧急提了个需求——双十一大促页面要支持“节日皮肤”,用户点击按钮就能切换红/金/蓝三种主题。产品经理画的原型图下午 3 点才给,要求晚上 8 点上线。

我们用的是 Styled Components + ThemeProvider。理论上,只要改 theme 对象就行。但实际开发时发现:

  • 动态加载的 SVG 图标颜色没法通过 theme 控制(因为内联 style 优先级高)
  • 第三方组件(比如 Ant Design)的样式还是得靠 !important 覆盖
  • 最致命的是,打包体积暴增了 120KB —— 因为每个组件都 inject 了 runtime 的 CSS 生成逻辑

最后我们不得不写了一堆 :global()css prop,代码丑得像被猫抓过的毛线球。上线后 Lighthouse 性能分直接从 92 掉到 76。

那一刻我突然明白:CSS-in-JS 不是银弹,它是一把需要精准操控的手术刀,而不是砍柴斧


三、传统 CSS 的“逆袭”:Tailwind 与 CSS Modules 的崛起

Gap 期间,我帮朋友做了个小工具网站(一个面向本地商家的库存管理 SaaS)。因为是 side project,我不想折腾复杂架构,就用了 Vite + React + Tailwind CSS。

结果出乎意料地爽。

  • <button className="bg-blue-500 hover:bg-blue-700 text-white py-2 px-4 rounded"> 比写 styled.button\...`` 快多了
  • 设计师给的设计稿可以直接用 Tailwind 的 spacing/palette 映射,不用再和 UI 同学扯“这个 margin 到底是 12px 还是 16px”
  • 最重要的是——构建速度飞快。Vite + Tailwind 的 HMR 几乎是瞬时的,而之前用 Emotion 时,改一行颜色都要等 3 秒

后来我又试了 CSS Modules。在另一个需要强隔离的项目里(一个多租户运营后台),我发现:

/* Button.module.css */
.primary {
  background: var(--color-primary);
  border-radius: 4px;
}
// Button.jsx
import styles from './Button.module.css';
export const Button = ({ variant }) => (
  <button className={styles[variant]}>Click</button>
);

没有运行时开销,没有 JS bundle 膨胀,还能享受局部作用域。配合 PostCSS 的 nesting 插件,写起来几乎和 SCSS 一样舒服。

我开始反思:当初在大厂推 CSS-in-JS,是不是有点“为了技术而技术”?毕竟大厂有专职的基建团队维护 Babel 插件、优化 bundle splitting,但中小团队哪有这种资源?


四、现实世界的权衡:不是技术选型,而是成本决策

上周终面时,技术负责人问我:“如果现在让你选,你会用哪种?”

我说:“看场景。”

然后列了三个维度:

1. 团队规模 & 技术栈

  • 如果团队里有 Java 后端(比如我前司),他们可能对前端“过度工程化”有天然抵触。这时候用传统 CSS + 约定式命名(BEM)反而沟通成本更低。
  • 但如果全是 React 老手,且项目重度依赖动态主题(比如设计系统、可视化平台),CSS-in-JS 的 DX(Developer Experience)优势就体现出来了。

2. 性能敏感度

  • 我做过 A/B 测试:同样一个含 50 个组件的页面,Emotion 版本首屏 JS bundle 比 CSS Modules 大 18%。
  • 对于内容型网站(比如新闻、博客),传统 CSS + 静态提取(如 Linaria)是更优解。
  • 但对于交互密集型应用(比如数据看板、运营活动页),JS 控制样式的灵活性更重要。

3. 长期维护成本

  • CSS-in-JS 的痛点在于“调试困难”。Chrome DevTools 里看到的是一堆 [data-emotion="css-xyz"],找具体样式要翻源码。
  • 而传统 CSS,至少能直接搜类名。特别是当运营同学半夜打电话说“首页按钮颜色不对”时,你能 30 秒定位问题。

说到这里,面试官笑了:“看来你真踩过坑。”


五、我的新认知:工具服务于人,而不是相反

裸辞这半年,最大的收获不是技术,而是学会区分“炫技”和“解决问题”

以前在大厂,总觉得不用最新技术就是落伍。但现在明白:一个优秀的工程师,不是会多少框架,而是知道在什么场景下该用什么工具

比如我现在的新工作(一家做跨境电商运营工具的公司),技术栈是:

  • 主应用:React + CSS Modules(因为要嵌入第三方店铺,不能污染全局样式)
  • 营销落地页:Next.js + Tailwind(快速迭代,SEO 友好)
  • 设计系统组件库:vanilla-extract(零运行时,支持类型安全)

没有一刀切,只有因地制宜


六、给正在纠结的你的建议

如果你也在选型,不妨问自己三个问题:

  1. 你的用户是谁

    • 如果是内部运营人员(比如 CRM、ERP),稳定性和可维护性 > 新潮技术
    • 如果是 C 端消费者(比如电商、社交),视觉一致性 & 加载速度更重要
  2. 你的团队有多少人

    • 3 人以下小团队:别碰 CSS-in-JS,除非你愿意花 20% 时间调构建配置
    • 10 人以上中台:可以考虑,但一定要配专职基建
  3. 你的老板关心什么

    • 如果老板是技术出身(比如前 Java 架构师),他会欣赏工程规范
    • 如果老板来自运营/销售,他只关心“明天能不能上线”

七、写在最后:房子、房贷与代码的哲学

昨天晚上,老婆问我:“这次工作稳定吗?要不要提前还点房贷?”

我说:“应该稳了。这次学聪明了,不盲目追新技术,先搞清楚业务要什么。”

其实写 CSS 也好,写 Java 也好,本质都一样:解决真实世界的问题,而不是满足自己的技术洁癖

CSS-in-JS 和传统 CSS 的争论,就像当年 jQuery 和原生 JS 的战争。最终胜出的,从来不是“最先进”的,而是“最合适”的。

我现在的小房子还在装修,水电工师傅昨天说:“管线要走直,但也要看墙里有没有钢筋。”
我想,写代码也一样。


P.S. 如果你也在杭州找前端岗,或者对样式方案有不同看法,欢迎私信交流(微信:chen_dev_2023)。最近建了个小群,都是 Gap 期互相打气的朋友,不灌鸡汤,只聊干货。

P.P.S. 别信网上那些“CSS-in-JS 已死”的文章。技术没有生死,只有适不适合。就像我老婆说的:“你管它什么方案,能按时还房贷就是好方案。”

评论 0

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