CSS-in-JS vs 传统CSS:一个35岁老码农的深夜抉择

掘金夜猫子
2025-12-19 00:34
阅读 1862

上周五晚上11点27分,我坐在出租屋的书桌前,手指在键盘上敲出第38个 styled.div,窗外是杭州下沙片区熟悉的车流声——其实也没啥车,主要是外卖小哥骑着电驴“突突”路过。老婆刚打完视频电话,说她那边武汉降温了,让我注意保暖。我嘴上应着“嗯嗯好”,心里却还在纠结:明天上线的新功能,到底该用 CSS-in-JS 还是传统 CSS?

这事儿说来有点荒诞。一个奔四的老程序员,本该在带团队、画架构图、喝枸杞茶,结果我还在为一行样式代码辗转反侧。更离谱的是,我们这个项目,居然是个区块链浏览器——对,就是那种用户量不大、但老板天天喊“颠覆行业”的玩意儿。

一、起因:那个要命的需求评审会

事情得从三天前说起。

产品经理小李(刚毕业两年,头发比我多)在会议室白板上画了个“交互原型”:用户点击某个NFT交易记录时,卡片要有“呼吸式高亮”,颜色还得根据区块高度动态渐变。他说:“这个效果要丝滑,不能有闪烁,最好还能支持深色模式。”

我心想:行吧,又是前端背锅日。

可问题来了——我们的项目目前用的是纯手写的 SCSS + BEM 命名规范,CSS 文件散落在十几个组件目录里。每次改个颜色,都得全局搜索 .btn--primary,生怕不小心改到另一个模块的同名类。

“要不要试试 Emotion 或者 Styled Components?”我试探性地问。

小李眼睛一亮:“可以啊!听说现在大厂都这么干!”

于是,一场关于“样式方案”的技术选型争论,在我们这个只有5个人的小团队里爆发了。

二、CSS-in-JS 的诱惑:像写 JavaScript 一样写样式

说实话,我对 CSS-in-JS 并不陌生。早在2018年,我就在 React Native 项目里用过 StyleSheet.create,那感觉就像给样式穿上了 JS 的外衣——逻辑和 UI 真正绑定在一起。

这次我试了 Emotion,因为它的 css prop 支持直接内联,还能配合 TypeScript 做类型检查。比如:

import { css } from '@emotion/react';

const Card = ({ blockHeight }) => {
  const gradientColor = `hsl(${blockHeight % 360}, 70%, 60%)`;
  
  return (
    <div
      css={css`
        background: linear-gradient(135deg, ${gradientColor}, #333);
        transition: all 0.3s ease;
        &:hover {
          transform: scale(1.02);
        }
      `}
    >
      NFT #{blockHeight}
    </div>
  );
};

看到没?样式逻辑直接嵌入组件,不用再翻三个文件夹找对应的 .scss。而且 blockHeight 是动态的,颜色随数据变化——这种“数据驱动样式”的能力,在传统 CSS 里得靠 style={{}} 内联或者加一堆 class 切换,既啰嗦又难维护。

更爽的是作用域隔离。再也不用担心 .card-title 被隔壁模块的同名类污染。每个组件的样式都是“私有财产”,符合现代前端“组件即单元”的思想。

那天晚上,我兴奋地给老婆发语音:“亲爱的,我发现了个好东西!以后改UI不用再怕全局污染了!”
她回:“哦,那你早点睡,别又熬到两点。”
我:“……你根本不懂我的快乐。”

三、但现实很快打了脸

上线前两天,性能测试报告出来了:首屏加载时间比之前多了 420ms

我懵了。赶紧打开 Chrome DevTools 的 Performance 面板,一看——好家伙,运行时解析 CSS 字符串占了大头。Emotion 在客户端要把那些模板字符串拼成真正的 CSS 规则,再插入 <style> 标签。对于一个区块链浏览器(页面动不动就渲染几百条交易记录),这开销不可忽视。

更糟的是 SEO。虽然我们不是内容型网站,但老板坚持要“对搜索引擎友好”。而服务端渲染(SSR)时,CSS-in-JS 需要额外配置才能把样式提取到 <head> 里。我折腾了一晚上,才让 Next.js 正确输出 critical CSS。

最让我焦虑的是调试体验。F12 里看到的 class 名全是 css-1x5b9zq 这种 hash 值,想手动改个颜色试试效果?得先找到对应组件,改代码,等热更新——而传统 CSS 直接在 Elements 面板里双击就能改。

那一刻,我坐在凌晨三点的电脑前,看着满屏的 hash 类名,突然有点怀念 .transaction-card--highlighted 这种朴实无华的名字。

四、传统 CSS 的倔强反击

于是我回头重拾老朋友:SCSS + CSS Modules

CSS Modules 让每个 .module.scss 文件里的类名自动局部化。比如:

// TransactionCard.module.scss
.card {
  background: #222;
  &--highlighted {
    animation: breathe 2s infinite;
  }
}

@keyframes breathe {
  0%, 100% { opacity: 0.8; }
  50% { opacity: 1; }
}
import styles from './TransactionCard.module.scss';

<div className={`${styles.card} ${isHighlighted ? styles['card--highlighted'] : ''}`}>

虽然写法啰嗦了点,但零运行时开销,构建时就把作用域搞定。而且 F12 里看到的类名至少能猜出来源(比如 TransactionCard_card__abc123)。

更重要的是,设计师给的 Design Token(比如颜色、间距系统)可以统一管理在 _variables.scss 里,前端、UI、甚至后端(如果他们用 SASS)都能共享。而 CSS-in-JS 得用 JS 对象存 theme,跨团队协作反而麻烦。

那天下午,我和小李复盘。我说:“咱们这项目,用户量不大,但数据密集、性能敏感,还要求 SSR。CSS-in-JS 的动态能力虽好,但有点‘杀鸡用牛刀’。”

他点点头:“那……要不混合用?核心列表用 CSS Modules,复杂交互动效用 Emotion?”

我笑了:“小伙子,终于学会妥协了。”

五、所以,到底该怎么选?

经过这轮折腾,我总结出一套“人话版”选择指南——不讲理论,只讲实战:

用 CSS-in-JS,如果你:

  • 项目重度依赖动态主题/运行时换肤(比如用户自定义配色)
  • 组件库开发,需要极致隔离(避免样式泄漏到宿主应用)
  • 团队全是 React 老手,且愿意接受调试成本
  • 不在乎那 100~500ms 的首屏损耗(比如内部工具)

用传统 CSS(+ Modules/SCSS),如果你:

  • 项目对性能极度敏感(电商、数据看板、区块链浏览器…)
  • 需要服务端渲染 + SEO
  • 团队有设计师,需要共享设计系统
  • 你是个35岁老码农,不想半夜被 hash 类名折磨

至于“区块链”这个关键词?其实它在这场争论中扮演了关键角色——区块链应用往往数据密集、UI 复杂、但用户量不大,这就决定了我们不能盲目追新。炫技解决不了 Gas Fee 高的问题,也解决不了用户看不懂钱包地址的困惑。

六、人到中年,技术选择更像生活选择

写这篇文章时,已经是周日凌晨。老婆刚发来消息:“你上次说想跳槽去深圳,考虑得怎么样了?”

我盯着屏幕,想起去年十月那次面试。HR问我:“你们项目用什么样式方案?”
我说:“CSS Modules 为主,复杂动画用少量 Emotion。”
他皱眉:“怎么不全上 Tailwind?”
我笑笑:“Tailwind 好,但不适合我们。”

最后 offer 拿到了,月薪从 22k 涨到 28k,但异地问题没解决。我和老婆商量后,决定再坚持一年——她在武汉的事业刚起步,我的技术债还没还清。

你看,技术选型和人生选择一样,没有“最优解”,只有“最适合当下处境的解”。

CSS-in-JS 不是银弹,传统 CSS 也不代表落后。关键在于:你的用户是谁?你的约束是什么?你的团队能承受多少复杂度?

就像我和老婆,异地很苦,但每周五晚上的视频电话,她说“今天做了你爱吃的藕汤”,我就觉得值得。

七、最后一点真心话

如果你也是个一线老码农,别被“必须用最新技术”绑架。Vue 3 很香,但 Vue 2 也能跑;TypeScript 是趋势,但 JS 写得好一样优雅。

技术是工具,不是身份标签。我们写代码,是为了交付价值,不是为了在简历上堆砌 buzzword。

下次当你纠结用哪种样式方案时,不妨问问自己:

  • 这个功能真的需要动态样式吗?
  • 我愿意为这点便利付出多少性能代价?
  • 半年后接手我代码的人,会骂我还是谢我?

答案自然就出来了。

好了,不写了。明天还得早起改 bug——据说有个用户反馈,深色模式下交易卡的“呼吸动画”看起来像“心电图停跳”,吓得他以为链挂了。

唉,这届用户,真难带。

(全文约 3612 字)

评论 0

最热最新
暂无评论
掘金夜猫子Lv.1
0
影响力
0
文章
0
粉丝