首页 / React 19 入门教程 / 样式方案

React 19 入门教程

样式方案

本教程共 50 篇 · 第 12 篇 · 更新于 2026-07-29 · 约 7 分钟阅读

ReactCSS样式CSS ModulesTailwindCSS-in-JSclassName

12. 样式方案

本节目标:了解 React 主流样式方案,掌握 className 用法,能根据项目需求选择合适的样式策略。

React 样式的本质

React 不规定你怎么写 CSS。所有方案最终都生成 CSS,区别只在于怎么组织作用域怎么控制

// 不管用哪种方案,JSX 里都是这样引用
<div className="card">内容</div>
Note

记住是 className 不是 class。这个坑我踩过不止一次。

方案一:普通 CSS

最直接的方式——写 .css 文件,在组件里 import

/* Card.css */
.card {
  border: 1px solid #ddd;
  border-radius: 8px;
  padding: 16px;
}

.card-title {
  font-size: 18px;
  font-weight: bold;
}
// Card.jsx
import './Card.css';

function Card({ title, children }) {
  return (
    <div className="card">
      <h2 className="card-title">{title}</h2>
      <div>{children}</div>
    </div>
  );
}

优点:简单、上手快、和传统写网页一样

缺点:全局作用域——class 名可能冲突。你定义一个 .button,我定义一个 .button,后写的覆盖先写的。

Tip

小项目或原型阶段用普通 CSS 就够了。项目一大就得上其他方案。

方案二:CSS Modules

CSS Modules 解决全局污染问题。每个 CSS 文件变成模块,类名自动生成唯一哈希。

/* Card.module.css */
.card {
  border: 1px solid #ddd;
  border-radius: 8px;
  padding: 16px;
}

.title {
  font-size: 18px;
  font-weight: bold;
}
// Card.jsx
import styles from './Card.module.css';

function Card({ title, children }) {
  return (
    <div className={styles.card}>
      <h2 className={styles.title}>{title}</h2>
      <div>{children}</div>
    </div>
  );
}

编译后类名会变成 Card_card_x7k9aCard_title_m3p2q,保证全局唯一。

优点:无冲突、可复用、和普通 CSS 写法一样

缺点:类名不能动态拼接(要用 classnames 库辅助)

Note

Vite 原生支持 CSS Modules——文件命名 xxx.module.css 即可,不需要额外配置。

方案三:Tailwind CSS

Tailwind 是原子化 CSS框架。不写 CSS 文件,直接在 className 里写工具类:

function Card({ title, children }) {
  return (
    <div className="border border-gray-200 rounded-lg p-4 shadow-sm">
      <h2 className="text-lg font-bold text-gray-800">{title}</h2>
      <div className="text-gray-600 mt-2">{children}</div>
    </div>
  );
}

每个类对应一个 CSS 属性——p-4padding: 1remtext-lgfont-size: 1.125rem

优点:开发效率高、无需起类名、最终打包只包含用到的样式

缺点:className 很长、需要记类名、HTML 可读性降低

// 极端例子:一个元素的 className 可能很长
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">

方案四:CSS-in-JS

CSS-in-JS 是在 JS 里写 CSS。以 styled-components 为例:

import styled from 'styled-components';

const Card = styled.div`
  border: 1px solid #ddd;
  border-radius: 8px;
  padding: 16px;
`;

const Title = styled.h2`
  font-size: 18px;
  font-weight: bold;
`;

function MyCard({ title, children }) {
  return (
    <Card>
      <Title>{title}</Title>
      <div>{children}</div>
    </Card>
  );
}

优点:完全隔离、能动态样式、组件化彻底

缺点:运行时开销、调试困难、学习成本高

内联 style 对象

React 支持直接传 style 对象:

function ColoredBox() {
  return (
    <div style={{
      backgroundColor: 'black',
      color: 'pink',
      padding: '16px',
    }}>
      内容
    </div>
  );
}

注意是 {{ 双括号——外层是 JSX 表达式,内层是对象字面量。CSS 属性名用驼峰。

Warning

内联样式不要用太多。它不支持伪类(:hover)、媒体查询、动画。只适合动态计算样式(比如根据状态变化的宽度)。

动态 className

根据条件切换 className 是最常见的需求:

function Button({ variant }) {
  return (
    <button className={variant === 'primary' ? 'btn-primary' : 'btn-default'}>
      按钮
    </button>
  );
}

多个条件叠加时,手动拼接会很乱。推荐用 classnames 库:

npm install classnames
import cn from 'classnames';

function Button({ variant, disabled, size }) {
  return (
    <button
      className={cn('btn', {
        'btn-primary': variant === 'primary',
        'btn-danger': variant === 'danger',
        'btn-disabled': disabled,
        'btn-sm': size === 'small',
        'btn-lg': size === 'large',
      })}
    >
      按钮
    </button>
  );
}

方案怎么选

方案适用场景学习成本
普通 CSS小项目、原型、学习阶段
CSS Modules中大型项目、需要隔离
Tailwind CSS快速开发、设计系统
CSS-in-JS组件库、动态主题
Tip

初学阶段推荐:普通 CSS → CSS Modules。等你有项目经验了,再考虑 Tailwind 或 CSS-in-JS。

实战示例

一个按钮组件,支持多种样式:

// Button.jsx
import styles from './Button.module.css';
import cn from 'classnames';

export default function Button({ variant = 'default', disabled, children }) {
  return (
    <button
      className={cn(
        styles.btn,
        styles[`btn-${variant}`],
        disabled && styles.disabled
      )}
      disabled={disabled}
    >
      {children}
    </button>
  );
}
/* Button.module.css */
.btn {
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.btn-default {
  background: #f0f0f0;
  color: #333;
}

.btn-primary {
  background: #1890ff;
  color: white;
}

.btn-danger {
  background: #ff4d4f;
  color: white;
}

.disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

本节小结

  • React 不规定样式方案,四种主流:普通 CSS、CSS Modules、Tailwind、CSS-in-JS
  • 记住用 className 不是 class
  • CSS Modules 解决命名冲突,Vite 原生支持
  • 内联 style 只适合动态值
  • 动态 className 用 classnames 库更优雅

到这里,模块一和模块二的内容全部学完了。你已经掌握了 React 的描述 UI 能力——组件、JSX、条件渲染、列表渲染、样式。

下一模块”添加交互”将进入事件处理和状态管理,让你的页面真正动起来。