CSS-in-JS vs 传统CSS:现代样式方案选择指南
——一个裸辞半年的前大厂程序员的深夜复盘
作者注:我是小陈,去年十月从阿里 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(零运行时,支持类型安全)
没有一刀切,只有因地制宜。
六、给正在纠结的你的建议
如果你也在选型,不妨问自己三个问题:
你的用户是谁?
- 如果是内部运营人员(比如 CRM、ERP),稳定性和可维护性 > 新潮技术
- 如果是 C 端消费者(比如电商、社交),视觉一致性 & 加载速度更重要
你的团队有多少人?
- 3 人以下小团队:别碰 CSS-in-JS,除非你愿意花 20% 时间调构建配置
- 10 人以上中台:可以考虑,但一定要配专职基建
你的老板关心什么?
- 如果老板是技术出身(比如前 Java 架构师),他会欣赏工程规范
- 如果老板来自运营/销售,他只关心“明天能不能上线”
七、写在最后:房子、房贷与代码的哲学
昨天晚上,老婆问我:“这次工作稳定吗?要不要提前还点房贷?”
我说:“应该稳了。这次学聪明了,不盲目追新技术,先搞清楚业务要什么。”
其实写 CSS 也好,写 Java 也好,本质都一样:解决真实世界的问题,而不是满足自己的技术洁癖。
CSS-in-JS 和传统 CSS 的争论,就像当年 jQuery 和原生 JS 的战争。最终胜出的,从来不是“最先进”的,而是“最合适”的。
我现在的小房子还在装修,水电工师傅昨天说:“管线要走直,但也要看墙里有没有钢筋。”
我想,写代码也一样。
P.S. 如果你也在杭州找前端岗,或者对样式方案有不同看法,欢迎私信交流(微信:chen_dev_2023)。最近建了个小群,都是 Gap 期互相打气的朋友,不灌鸡汤,只聊干货。
P.P.S. 别信网上那些“CSS-in-JS 已死”的文章。技术没有生死,只有适不适合。就像我老婆说的:“你管它什么方案,能按时还房贷就是好方案。”

评论 0