面试题:React 中引入 CSS 的方式有哪些?

这是一道考察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-primarybtnPrimary
  • 动态样式需要额外方案

适用: 大多数中大型React项目(Create React App默认支持)


3. CSS-in-JS(运行时方案)

用JavaScript写CSS,如styled-componentsEmotion

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 ModulesTailwind CSS

场景2:中大型企业项目

CSS Modules + Sassstyled-components

场景3:组件库开发

CSS-in-JS(支持主题)或 CSS Modules

场景4:需要服务端渲染(SSR)

CSS ModulesTailwind(CSS-in-JS有闪烁问题)

场景5:重度动态样式(主题切换)

CSS-in-JS(如styled-components)


四、常见面试追问

追问1:CSS Modules的原理是什么?

答: Webpack在构建时对CSS文件进行处理:

  1. 解析CSS类名
  2. 生成唯一的哈希类名(如Button_btn__2x1Kl
  3. 替换JSX中的类名引用
  4. 导出映射对象({ btn: 'Button_btn__2x1Kl' }

追问2:styled-components和Emotion的区别?

答:

  • Emotion:更轻量,API更灵活(支持css prop)
  • styled-components:社区更大,生态更完善
  • 两者核心原理相同,性能相近

追问3:如何解决CSS Modules中的全局样式?

答:

:global(.global-class) {
  /* 不会被哈希化 */
}

:local(.localClass) {
  /* 默认行为,会被哈希化 */
}

追问4:CSS-in-JS的性能问题如何优化?

答:

  1. 使用零运行时方案(如Linaria、Vanilla Extract)
  2. 避免在render中创建样式
  3. 使用shouldForwardProp减少DOM属性
  4. 生产环境使用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
THE END
喜欢就支持一下吧
点赞14 分享