这是一道考察React样式方案生态的面试题,能体现你对工程化实践的了解程度。
下面从6种主流方式进行对比分析,涵盖从基础到进阶的方案。
一、快速对比总览
| 方式 | 作用域 | 动态样式 | 预处理器 | 适用场景 |
|---|---|---|---|---|
| 全局CSS | 全局 | ❌ | ✅ | 简单项目、重置样式 |
| CSS Modules | 局部 | ❌ | ✅ | 中大型项目(推荐) |
| CSS-in-JS | 局部 | ✅ | ✅ | 重度动态样式、组件库 |
| Sass/Less | 全局/局部 | ❌ | ✅ | 需要变量/嵌套的项目 |
| Tailwind CSS | 全局 | ❌ | ❌ | 快速开发、团队协作 |
| Styled Components | 局部 | ✅ | ✅ | React专用、动态主题 |
二、6种方式详解
1. 全局CSS(传统方式)
直接导入.css文件,样式全局生效。
// App.jsx
import './App.css';
function App() {
return <div className="container">Hello</div>;
}
/* App.css */
.container {
padding: 20px;
}
优点:
- 简单直接,无学习成本
- 支持预处理器(Sass/Less)
缺点:
- 全局作用域,容易命名冲突
- 样式依赖难以追踪
- 无法处理动态样式
适用: 极简项目、全局样式(如reset.css)
2. CSS Modules(官方推荐)
文件名使用[name].module.css,样式自动局部作用域。
// Button.jsx
import styles from './Button.module.css';
function Button() {
return <button className={styles.btn}>Click</button>;
}
/* Button.module.css */
.btn {
background: blue;
color: white;
}
编译后类名变成唯一哈希:Button_btn__2x1Kl
优点:
- 真正的局部作用域
- 无运行时开销
- 支持组合(
composes) - 与普通CSS写法一致
缺点:
- 类名用驼峰(
btn-primary→btnPrimary) - 动态样式需要额外方案
适用: 大多数中大型React项目(Create React App默认支持)
3. CSS-in-JS(运行时方案)
用JavaScript写CSS,如styled-components、Emotion。
import styled from 'styled-components';
const Button = styled.button`
background: ${props => props.primary ? 'blue' : 'gray'};
color: white;
padding: 10px;
`;
function App() {
return <Button primary>Click</Button>;
}
优点:
- 真正的动态样式(props/theme)
- 样式与组件强绑定
- 自动生成唯一类名
- 支持主题切换
缺点:
- 运行时性能开销
- 打包体积增大
- 增加学习成本
- TypeScript支持需要额外配置
适用: 重度动态样式、设计系统、组件库
4. Sass/Less + CSS Modules
结合预处理器和CSS Modules。
// Button.module.scss
.btn {
$primary-color: #1890ff;
background: $primary-color;
&:hover {
opacity: 0.8;
}
}
import styles from './Button.module.scss';
优点:
- 变量、嵌套、混合等强大功能
- 保持局部作用域
- 构建时处理,无运行时开销
缺点:
- 需要配置webpack
- 动态样式仍需其他方案
适用: 追求CSS完整功能的大型项目
5. Tailwind CSS(原子化CSS)
通过工具类快速构建界面。
function Button() {
return (
<button className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">
Click
</button>
);
}
优点:
- 开发速度快
- 打包体积小(未使用的样式会被擦除)
- 设计系统一致性
- 无需写CSS
缺点:
- class列表冗长
- 学习记忆成本
- 动态类名需要特殊处理
适用: 快速开发、团队协作、需要设计约束的项目
6. 内联样式(Inline Style)
直接通过style属性写样式。
function Button({ color }) {
return (
<button style={{
backgroundColor: color,
padding: '10px 20px',
'&:hover': { // ❌ 伪类不支持
backgroundColor: 'darkblue'
}
}}>
Click
</button>
);
}
优点:
- 完全动态
- 无作用域问题
缺点:
- 不支持伪类、媒体查询
- 不支持动画
- 没有自动补全
- 性能较差(每次创建新对象)
适用: 少量动态样式(如进度条宽度)
三、实际项目选型建议
场景1:个人项目/小型项目
→ CSS Modules 或 Tailwind CSS
场景2:中大型企业项目
→ CSS Modules + Sass 或 styled-components
场景3:组件库开发
→ CSS-in-JS(支持主题)或 CSS Modules
场景4:需要服务端渲染(SSR)
→ CSS Modules 或 Tailwind(CSS-in-JS有闪烁问题)
场景5:重度动态样式(主题切换)
→ CSS-in-JS(如styled-components)
四、常见面试追问
追问1:CSS Modules的原理是什么?
答: Webpack在构建时对CSS文件进行处理:
- 解析CSS类名
- 生成唯一的哈希类名(如
Button_btn__2x1Kl) - 替换JSX中的类名引用
- 导出映射对象(
{ btn: 'Button_btn__2x1Kl' })
追问2:styled-components和Emotion的区别?
答:
- Emotion:更轻量,API更灵活(支持
cssprop) - styled-components:社区更大,生态更完善
- 两者核心原理相同,性能相近
追问3:如何解决CSS Modules中的全局样式?
答:
:global(.global-class) {
/* 不会被哈希化 */
}
:local(.localClass) {
/* 默认行为,会被哈希化 */
}
追问4:CSS-in-JS的性能问题如何优化?
答:
- 使用零运行时方案(如Linaria、Vanilla Extract)
- 避免在render中创建样式
- 使用
shouldForwardProp减少DOM属性 - 生产环境使用
babel-plugin-styled-components提取静态样式
五、面试参考答案(精简版)
“React中引入CSS有6种主流方式:全局CSS、CSS Modules、CSS-in-JS、预处理器(Sass/Less)、原子化CSS(Tailwind)、内联样式。其中,CSS Modules是官方推荐的方案,兼具局部作用域和零运行时开销;CSS-in-JS适合重度动态样式场景;Tailwind CSS适合追求开发效率和设计系统一致性的项目。在实际项目中,我倾向于使用CSS Modules + Sass的组合,既能获得局部作用域,又能使用预处理器的高级功能。”
快速决策流程图
是否需要动态样式?
├─ 是 → 是否需要SSR?
│ ├─ 是 → CSS Modules + CSS变量
│ └─ 否 → CSS-in-JS(styled-components)
└─ 否 → 是否需要局部作用域?
├─ 是 → CSS Modules
└─ 否 → Tailwind CSS / 全局CSS



