CSS全局性、顺序敏感和无作用域导致样式冲突;CSS-in-JS适用于需运行时控制样式的场景,如动态主题与权限组合计算;应分离基础样式(reset/fonts)与组件逻辑样式,避免滥用styled()污染全局。

大型项目里直接 import 一堆 CSS 文件为什么总出事
因为 CSS 的全局性、顺序敏感性和无作用域,import 'antd/dist/antd.css' 和 import './Button.module.css' 一混,就容易覆盖、泄漏、冲突。不是样式没生效,而是你根本不知道谁在什么时候改了 .ant-btn 的 padding。
- 常见错误现象:
!important越写越多、主题切换后部分组件不响应、构建后样式丢失(但开发时正常) - 使用场景:中后台系统、多团队协作、需要动态换肤或 AB 实验的前端项目
- 关键问题不在“要不要用 CSS-in-JS”,而在于“是否需要运行时控制样式逻辑”——比如按钮禁用态的颜色要根据当前主题 + 权限级别双重计算
styled-components vs. Emotion:选哪个看你的打包链路
styled-components 和 @emotion/react 都支持动态插值和主题透传,但构建行为差异很大。如果你用 Webpack 5 + Module Federation 或 Vite 的 build.lib 模式,@emotion/react 更稳。
-
styled-components的StyleSheetManager在微前端子应用里容易漏掉target,导致样式插入到主应用 head 中,造成污染 -
@emotion/react的CacheProvider支持显式key隔离,配合createCache({ key: 'app-a' })可避免跨子应用样式冲突 - 两者都依赖 Babel 插件(
babel-plugin-styled-components/@emotion/babel-plugin),漏配会导致服务端渲染时 className 不一致
不要把所有 CSS 都塞进 styled() 函数里
字体、重置、基础排版、图标字体这些跟业务逻辑无关的样式,依然该走传统 CSS 文件加载。CSS-in-JS 的价值是「让样式成为组件状态的函数」,不是「把所有 class 搬进 JS」。
- 错误做法:
const Wrapper = styled.div`body { margin: 0; font-family: sans-serif; }`—— 这会重复注入、无法复用、破坏 SSR 一致性 - 正确分工:用
reset.css+fonts.css通过 HTML<link>加载;用styled管理Button的loading、size、variant衍生样式 - 性能影响:每个
styled组件首次渲染都会生成唯一 className 并注入 style 标签,高频更新组件(如表格行)建议用cssprop +useMemo缓存样式对象
主题切换时,CSS-in-JS 的变量怎么不爆红
别用 process.env.THEME === 'dark' 做条件判断生成样式字符串,那会破坏 SSR 和样式提取。主题必须是运行时可变的状态,且所有样式计算得支持重新求值。
立即学习“前端免费学习笔记(深入)”;
- 推荐路径:用 React Context 提供
theme对象,再配合styled的插值函数(props => props.theme.colors.primary) - 容易踩的坑:
ThemeProvider必须包裹整个应用(包括 Suspense fallback),否则异步加载的组件拿不到 theme;自定义 hook 里调用useTheme()前要确认它不在 SSR 期间被误执行 - 兼容性注意:Next.js App Router 默认禁用
styled-components的服务端样式注入,得手动配置styled-components的AppRouterAdapter或切到@emotion/react
extract-css-chunks-webpack-plugin 或 @emotion/server,导致首屏闪白。这些点不卡在文档里,卡在第一次部署后的用户反馈里。


















