在这里插入图片描述

样式处理方案

一、样式处理方式概览

在 React 中,有多种处理样式的方法,每种都有其适用场景。

方式 适用场景 优点 缺点
行内样式 动态样式、简单组件 直观、动态 性能差、不支持伪类
CSS 模块 中小型项目 作用域隔离、简单 需要配置
CSS-in-JS 大型项目、组件库 动态、类型安全 运行时开销
Tailwind CSS 快速开发 实用优先、体积小 学习曲线
Less/Sass 传统项目 功能丰富 全局作用域

二、行内样式 (Inline Styles)

2.1 基础用法

function Button() {
  const buttonStyle = {
    backgroundColor: '#007bff',
    color: 'white',
    padding: '10px 20px',
    border: 'none',
    borderRadius: '4px',
    cursor: 'pointer'
  };

  return <button style={buttonStyle}>点击我</button>;
}

2.2 动态样式

function DynamicButton({ primary, disabled }) {
  const styles = {
    backgroundColor: primary ? '#007bff' : '#6c757d',
    color: 'white',
    padding: '10px 20px',
    opacity: disabled ? 0.5 : 1,
    cursor: disabled ? 'not-allowed' : 'pointer'
  };

  return <button style={styles} disabled={disabled}>按钮</button>;
}

2.3 条件样式合并

function StatusBadge({ status }) {
  const baseStyles = {
    padding: '4px 8px',
    borderRadius: '4px',
    fontSize: '12px'
  };

  const statusStyles = {
    success: { backgroundColor: '#28a745', color: 'white' },
    warning: { backgroundColor: '#ffc107', color: '#333' },
    error: { backgroundColor: '#dc3545', color: 'white' }
  };

  return (
    <span style={{ ...baseStyles, ...statusStyles[status] }}>
      {status}
    </span>
  );
}

三、CSS 模块 (CSS Modules)

3.1 创建 CSS 模块文件

Button.module.css

.button {
  background-color: #007bff;
  color: white;
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
}

.buttonPrimary {
  background-color: #007bff;
}

.buttonSecondary {
  background-color: #6c757d;
}

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

3.2 使用 CSS 模块

import styles from './Button.module.css';

function Button({ variant = 'primary', disabled }) {
  const buttonClass = `
    ${styles.button}
    ${variant === 'primary' ? styles.buttonPrimary : styles.buttonSecondary}
    ${disabled ? styles.disabled : ''}
  `;

  return <button className={buttonClass} disabled={disabled}>按钮</button>;
}

3.3 组合样式

import styles from './Card.module.css';

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

四、CSS-in-JS (Styled Components)

4.1 安装与配置

npm install styled-components

4.2 基础使用

import styled from 'styled-components';

const Button = styled.button`
  background-color: #007bff;
  color: white;
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  
  &:hover {
    background-color: #0056b3;
  }
  
  &:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }
`;

function App() {
  return <Button>点击我</Button>;
}

4.3 动态样式

const Button = styled.button`
  background-color: ${props => props.primary ? '#007bff' : '#6c757d'};
  color: white;
  padding: ${props => props.large ? '12px 24px' : '8px 16px'};
  font-size: ${props => props.large ? '16px' : '14px'};
  border: none;
  border-radius: 4px;
  cursor: pointer;
  
  &:hover {
    background-color: ${props => props.primary ? '#0056b3' : '#5a6268'};
  }
`;

function App() {
  return (
    <div>
      <Button primary>主要按钮</Button>
      <Button>次要按钮</Button>
      <Button large primary>大号按钮</Button>
    </div>
  );
}

4.4 样式继承

const BaseButton = styled.button`
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
`;

const PrimaryButton = styled(BaseButton)`
  background-color: #007bff;
  color: white;
  
  &:hover {
    background-color: #0056b3;
  }
`;

const SecondaryButton = styled(BaseButton)`
  background-color: #6c757d;
  color: white;
`;

五、Tailwind CSS

5.1 安装配置

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

5.2 基础使用

function Button({ children, primary }) {
  return (
    <button
      className={`
        px-4 py-2 rounded font-semibold
        ${primary 
          ? 'bg-blue-500 text-white hover:bg-blue-600' 
          : 'bg-gray-500 text-white hover:bg-gray-600'
        }
      `}
    >
      {children}
    </button>
  );
}

5.3 条件样式

function Card({ variant, children }) {
  const variants = {
    default: 'bg-white border-gray-200',
    primary: 'bg-blue-50 border-blue-200',
    warning: 'bg-yellow-50 border-yellow-200',
    error: 'bg-red-50 border-red-200'
  };

  return (
    <div className={`p-4 border rounded-lg shadow ${variants[variant]}`}>
      {children}
    </div>
  );
}

5.4 使用 clsx 简化类名

npm install clsx
import clsx from 'clsx';

function Button({ primary, size = 'medium', disabled }) {
  return (
    <button
      className={clsx(
        'rounded font-semibold transition-colors',
        {
          'bg-blue-500 text-white hover:bg-blue-600': primary,
          'bg-gray-500 text-white hover:bg-gray-600': !primary,
          'px-2 py-1 text-sm': size === 'small',
          'px-4 py-2 text-base': size === 'medium',
          'px-6 py-3 text-lg': size === 'large',
          'opacity-50 cursor-not-allowed': disabled
        }
      )}
      disabled={disabled}
    >
      按钮
    </button>
  );
}

六、Less/Sass

6.1 安装

npm install sass

6.2 创建 SCSS 文件

styles/variables.scss

$primary-color: #007bff;
$secondary-color: #6c757d;
$border-radius: 4px;

Button.scss

@import './variables';

.button {
  padding: 10px 20px;
  border: none;
  border-radius: $border-radius;
  cursor: pointer;
  
  &-primary {
    background-color: $primary-color;
    color: white;
    
    &:hover {
      background-color: darken($primary-color, 10%);
    }
  }
  
  &-secondary {
    background-color: $secondary-color;
    color: white;
  }
}

6.3 在 React 中使用

import './Button.scss';

function Button({ variant = 'primary', children }) {
  return (
    <button className={`button button-${variant}`}>
      {children}
    </button>
  );
}

七、样式优先级与最佳实践

7.1 样式优先级顺序

  1. 行内样式 - 优先级最高(不推荐过度使用)
  2. CSS 模块 - 作用域隔离,优先级中等
  3. 全局 CSS - 优先级最低

7.2 最佳实践建议

// ✅ 使用 CSS 变量实现主题
const theme = {
  colors: {
    primary: '#007bff',
    secondary: '#6c757d',
    success: '#28a745',
    danger: '#dc3545'
  },
  spacing: {
    sm: '8px',
    md: '16px',
    lg: '24px'
  }
};

// ✅ 提取公共样式
const commonStyles = {
  flexCenter: {
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center'
  }
};

// ✅ 使用 CSS 变量
// global.css
:root {
  --primary-color: #007bff;
  --text-color: #333;
}

// 组件中使用
<div style={{ color: 'var(--text-color)' }}>内容</div>

八、性能优化建议

问题 解决方案
CSS-in-JS 运行时开销 使用零运行时方案(Linaria、Vanilla Extract)
样式重复计算 使用 styled-components 的 babel 插件
全局样式污染 使用 CSS 模块或 CSS-in-JS
未使用的样式 使用 PurgeCSS(Tailwind 自带)

九、练习题

基础题

  1. 创建一个卡片组件,支持不同主题(light/dark)
  2. 实现一个按钮组件,支持 primary、secondary、danger 三种变体

进阶题

  1. 实现一个响应式导航栏,移动端显示汉堡菜单
  2. 创建一个支持主题切换的组件(亮色/暗色模式)

参考答案

// 1. 主题切换组件
const ThemeContext = React.createContext();

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');
  const toggleTheme = () => setTheme(theme === 'light' ? 'dark' : 'light');
  
  const themeStyles = {
    light: {
      backgroundColor: '#fff',
      color: '#333'
    },
    dark: {
      backgroundColor: '#333',
      color: '#fff'
    }
  };
  
  return (
    <ThemeContext.Provider value={{ theme, toggleTheme, themeStyles: themeStyles[theme] }}>
      {children}
    </ThemeContext.Provider>
  );
}

// 2. 响应式导航栏(CSS 模块 + 媒体查询)
// Navbar.module.css
.nav {
  display: flex;
  justify-content: space-between;
  padding: 1rem;
}

.menu {
  display: flex;
  gap: 1rem;
}

.hamburger {
  display: none;
}

@media (max-width: 768px) {
  .menu {
    display: none;
  }
  
  .menuOpen {
    display: flex;
    flex-direction: column;
    position: absolute;
    top: 60px;
    left: 0;
    right: 0;
    background: white;
    padding: 1rem;
  }
  
  .hamburger {
    display: block;
  }
}

十、小结

场景 推荐方案
快速原型 Tailwind CSS
组件库开发 CSS-in-JS (styled-components)
中小型项目 CSS 模块
大型应用 CSS-in-JS + CSS 变量
现有项目迁移 Less/Sass

核心要点

  • 根据项目规模选择合适的方案
  • 保持样式的一致性
  • 注意性能影响
  • 优先使用作用域隔离

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐