Skip to content
样式方案

样式方案

React 项目中处理 CSS 的七种主流方案,从最传统的全局 CSS 到现代的原子化方案。


方案对比

方案 作用域 学习曲线 包体积 动态样式 适用场景
全局 CSS 全局 最低 0 极简项目
CSS Modules 局部 0 中大型项目
Tailwind CSS 工具类 ~3KB (不包含 purge) 部分 追求开发速度
styled-components 局部 ~13KB 动态样式多
CSS-in-JS (Emotion/Panda) 局部 ~8KB 同上
Inline Style 局部 最低 0 简单动态样式
UI 组件库 全局/局部 大 (50KB+) 部分 快速原型/后台

方案一:全局 CSS

/* styles.css */
.button {
  background: #3b82f6;
  color: white;
  padding: 8px 16px;
  border-radius: 4px;
}
// main.jsx — 入口文件引入一次,全局生效
import './styles.css';

<button className="button">Click</button>

🚨 陷阱:全局 CSS 命名冲突。BEM 命名规范可以缓解(如 .card__header--large),但无法彻底避免。快速原型阶段可用,正式项目优先选择有作用域的方案。


方案二:CSS Modules(推荐)

Vite 默认支持 .module.css 文件:

/* Button.module.css */
.button {
  background: #3b82f6;
  color: white;
  padding: 8px 16px;
}

.variantOutline {
  background: transparent;
  border: 2px solid #3b82f6;
  color: #3b82f6;
}
import styles from './Button.module.css';

function Button({ variant }) {
  return (
    <button className={`${styles.button} ${variant === 'outline' ? styles.variantOutline : ''}`}>
      Submit
    </button>
  );
}

产物中类名自动加哈希:

/* 编译后 */
.Button_button__xk2p4 { background: #3b82f6; }

CSS Modules 组合

/* 扩展已有的类 */
.error {
  composes: alert from './Alert.module.css';
  background: red;
}

CSS Modules 最佳实践

💡 最佳实践

  • 一个组件一个 .module.css 文件,放在组件旁边
  • styles.xxx 访问类名,让拼写错误在编译时暴露(TypeScript 项目用 .module.css.d.ts 或 Vite 的类型插件)
  • 多个类名组合用 clsx 辅助库:clsx(styles.button, isActive && styles.active)

方案三:Tailwind CSS

npm install -D tailwindcss @tailwindcss/vite
function Card({ title, children }) {
  return (
    <div className="bg-white rounded-lg shadow-md p-6 hover:shadow-lg transition-shadow">
      <h2 className="text-lg font-semibold text-gray-900 mb-4">{title}</h2>
      <div className="text-gray-600">{children}</div>
    </div>
  );
}

Tailwind 的优势与争议

优势 争议
快速原型和开发 HTML 看起来很"脏"
天然的作用域(无样式泄漏) 长类名列表可读性差
设计系统内建(spacing/color/typography) 学习工具类名有成本
CSS 体积恒定(purge 后约 3-5KB) 复杂动画仍需写 CSS

💡 最佳实践:长列表的类名组合可以用 clsxtailwind-merge 管理,抽取重复样式为组件。Tailwind v4 引入 CSS-first 配置,大幅简化了配置流程。


方案四:CSS-in-JS(styled-components)

npm install styled-components
import styled from 'styled-components';

const Button = styled.button`
  background: ${props => props.$primary ? '#3b82f6' : '#e5e7eb'};
  color: ${props => props.$primary ? 'white' : '#374151'};
  padding: 8px 16px;
  border-radius: 4px;
  border: none;
  cursor: pointer;

  &:hover {
    opacity: 0.9;
  }
`;

// 使用
<Button $primary>提交</Button>
<Button>取消</Button>

特点

优点 缺点
真正的动态样式(基于 props) 运行时开销(JS 生成 CSS)
无需单独 CSS 文件 包体积增加
自动厂商前缀 SSR 配置复杂
CSS 语法高亮(编辑器插件) 难以使用传统 CSS 工具

性能提示:CSS-in-JS 方案在运行时生成样式注入到 DOM(约 4-8ms 开销/次渲染)。对大多数应用影响不大,但高频渲染场景(动画、大列表)应避免。


方案五:零运行时 CSS(Panda CSS / Vanilla Extract)

新一代 CSS-in-JS 在构建时生成静态 CSS——既有类型安全的 DX,又无运行时开销:

// Panda CSS
import { css } from '../styled-system/css';

function Button() {
  return (
    <button className={css({
      bg: 'blue.500',
      color: 'white',
      px: '4',
      py: '2',
      rounded: 'md',
    })}>
      Submit
    </button>
  );
}

构建时生成纯 CSS 文件,运行时零开销。


方案六:UI 组件库

样式方案 特点
Ant Design CSS-in-JS (v5) 企业级,组件最全面
shadcn/ui Tailwind + Radix 复制源码到项目,完全可定制
MUI Emotion Material Design,生态好
Chakra UI Emotion 开发体验好,组合性强
NextUI Tailwind 基于 React Aria,现代风格

💡 最佳实践:shadcn/ui 目前是社区首选——它不属于"依赖",而是直接复制源码到你的项目,意味着完全可控制和定制。


方案七:Inline Style

<div style={{ color: 'red', fontSize: 16 }}>
  Hello
</div>
适用 不适用
依赖 JS 数据的动态值 伪类(:hover)
少数几个属性 伪元素(::before)
位置/大小计算 媒体查询
动画

💡 最佳实践:inline style 适合组合其他方案使用。例如用 Tailwind 做静态样式 + inline style 做动态值。


选择决策

项目大小?
  ├── 极简(几个页面) → 全局 CSS 或 inline
  ├── 小型 → Tailwind CSS
  ├── 中型 →
  │     ├── 追求开发速度 → Tailwind + shadcn/ui
  │     ├── 追求传统分离 → CSS Modules
  │     └── 大量动态样式 → styled-components / Panda CSS
  └── 大型 → 团队统一选择(Tailwind / CSS Modules / Panda CSS)