现代项目采用 css-in-js 是为解决命名冲突、状态耦合和跨包复用问题;其核心优势在于运行时生成稳定哈希类名、支持 props 驱动的样式逻辑、内联关键样式提升首屏性能,但需配合 babel 插件、统一 cache 实例等细节才能落地生效。

现代项目用 CSS-in-JS,不是因为“更潮”,而是独立 CSS 文件在组件化场景下已经扛不住命名冲突、状态耦合和跨包复用这三类实际问题。
组件内样式被第三方库覆盖怎么办
你在 Button 组件里写了 .btn,Ant Design 也导出 .btn;哪怕开了 css-modules,SSR 时两端生成的 hash 不一致,照样覆盖。这不是理论风险,是上线后真会发生的样式错乱。
- styled-components 和 emotion 在运行时按组件定义+props 结构生成稳定 hash(如
sc-kVfIPa或css-1x2a3cd),不依赖文件路径 - 同一组件多次渲染 → 类名相同,利于
<style></style>标签复用 - 服务端与客户端类名一致,需启用
@emotion/babel-plugin或styled-components/babel
props 驱动的样式写成 className 字符串拼接太脆
一个 Input 要响应 error、disabled、size、variant 四个 prop,16 种组合。传统写法:className={`${base} ${error ? 'error' : ''} ${disabled ? 'disabled' : ''}`} —— 可读性差、难测试、主题切换要重写整套 class 名。
- 用
styled.input直接写逻辑:border: 1px solid ${props => props.error ? '#f33' : '#ccc'}; - 所有计算发生在 render 阶段,结果会被缓存(emotion 的
css函数传对象还能进一步避免重复计算) - 变量、三元、函数调用、import 共享色值常量,全都能用,不是“把 CSS 写进 JS”,是让样式获得 JS 表达力
Emotion 比传统 CSS 快?前提是你没踩坑
Emotion 首屏快,是因为关键样式能内联进 HTML,跳过 <link rel="stylesheet"> 的网络阻塞和解析等待。但这个优势很脆弱。
- 未启用 Babel 插件 → 静态样式被迫推到运行时,拖慢首屏
- 每次渲染都新建样式对象(如
{ fontSize: props.size + 'px' })→ 破坏哈希缓存,重复插入规则 - 多个包装了不同版本的
@emotion/cache→ cache 实例不共享,样式重复注入 - 在
useEffect或事件回调里调用css→ 绕过序列化优化路径
真正决定性能的,不是“用了 CSS-in-JS”,而是你是否约束动态逻辑范围、是否统一 cache 实例、是否让 Babel 插件提前处理静态部分——这些细节,比选库本身更影响落地效果。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











