React 样式语法知识点与案例详解

作为React初学者,掌握样式语法是构建美观UI的关键。本文将详细介绍React中所有主要的样式方法,并提供详细注释的案例代码。

一、React样式语法知识点总览

1. 行内样式 (Inline Styles)

  • 使用style属性,值为JavaScript对象
  • 属性名采用驼峰命名法
  • 值为字符串或数字

2. CSS样式表 (CSS Stylesheets)

  • 传统的CSS文件引入方式
  • 使用className而非class

3. CSS Modules

  • 局部作用域的CSS
  • 避免样式冲突
  • 文件名通常为[name].module.css

4. CSS-in-JS库 (Styled-components)

  • 在JavaScript中编写CSS
  • 动态样式支持良好
  • 组件即样式

5. 使用Sass/SCSS预处理器

  • 支持变量、嵌套、混合等功能
  • 文件扩展名为.scss.sass

6. 使用Tailwind CSS

  • 实用优先的CSS框架
  • 直接在className中使用实用类

7. 条件样式

  • 根据状态或props动态应用样式
  • 使用三元运算符或逻辑运算符

8. 动态样式

  • 根据数据或用户交互改变样式
  • 结合状态管理使用

二、详细案例代码

案例1:行内样式 (Inline Styles)

import React, { useState } from 'react';

function InlineStyleExample() {
  // 定义样式对象 - 注意驼峰命名法
  const containerStyle = {
    padding: '20px',
    backgroundColor: '#f0f0f0',
    borderRadius: '8px',
    margin: '10px 0',
    fontFamily: 'Arial, sans-serif'
  };

  const buttonStyle = {
    backgroundColor: '#007bff',
    color: 'white',
    border: 'none',
    padding: '10px 20px',
    borderRadius: '4px',
    cursor: 'pointer',
    fontSize: '16px',
    marginRight: '10px'
  };

  const hoverButtonStyle = {
    ...buttonStyle, // 使用展开运算符继承基础样式
    backgroundColor: '#0056b3', // 覆盖背景色
    transform: 'scale(1.05)', // 添加缩放效果
    transition: 'all 0.3s ease' // 添加过渡效果
  };

  // 状态管理用于动态样式
  const [isHovered, setIsHovered] = useState(false);
  const [fontSize, setFontSize] = useState(16);

  return (
    <div style={containerStyle}>
      <h2 style={{ 
        color: '#333', 
        marginBottom: '20px',
        textAlign: 'center'
      }}>
        行内样式示例
      </h2>
      
      {/* 基础按钮样式 */}
      <button 
        style={buttonStyle}
        onMouseEnter={() => setIsHovered(true)}
        onMouseLeave={() => setIsHovered(false)}
      >
        基础按钮
      </button>
      
      {/* 动态按钮样式 - 根据hover状态改变 */}
      <button 
        style={isHovered ? hoverButtonStyle : buttonStyle}
      >
        {isHovered ? '鼠标悬停中' : '悬停我'}
      </button>
      
      {/* 根据状态动态改变字体大小 */}
      <div style={{ marginTop: '20px' }}>
        <p style={{ 
          fontSize: `${fontSize}px`,
          transition: 'font-size 0.3s ease'
        }}>
          当前字体大小: {fontSize}px
        </p>
        <button 
          style={buttonStyle}
          onClick={() => setFontSize(prev => Math.min(prev + 2, 32))}
        >
          增大字体
        </button>
        <button 
          style={buttonStyle}
          onClick={() => setFontSize(prev => Math.max(prev - 2, 12))}
        >
          减小字体
        </button>
      </div>
      
      {/* 复杂的动态样式示例 */}
      <div style={{
        marginTop: '30px',
        padding: '15px',
        backgroundColor: isHovered ? '#e9ecef' : '#ffffff',
        border: `2px solid ${isHovered ? '#007bff' : '#dee2e6'}`,
        borderRadius: '8px',
        transition: 'all 0.3s ease',
        cursor: 'pointer'
      }} 
        onMouseEnter={() => setIsHovered(true)}
        onMouseLeave={() => setIsHovered(false)}
      >
        <p>这个盒子的样式会根据鼠标悬停状态动态改变</p>
        <p style={{ fontStyle: 'italic', color: '#6c757d' }}>
          {isHovered ? '鼠标正在悬停' : '请将鼠标悬停在此处'}
        </p>
      </div>
    </div>
  );
}

export default InlineStyleExample;

案例2:CSS样式表 (CSS Stylesheets)

首先创建 StylesheetExample.css 文件:

/* StylesheetExample.css */
.card-container {
  padding: 20px;
  background-color: #f8f9fa;
  border-radius: 8px;
  margin: 20px 0;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  font-family: 'Arial', sans-serif;
}

.card-title {
  color: #343a40;
  font-size: 24px;
  margin-bottom: 15px;
  text-align: center;
  border-bottom: 2px solid #007bff;
  padding-bottom: 10px;
}

.card-content {
  background-color: white;
  padding: 15px;
  border-radius: 4px;
  margin: 15px 0;
  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}

.button-group {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin-top: 20px;
}

.btn {
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 16px;
  transition: all 0.3s ease;
}

.btn-primary {
  background-color: #007bff;
  color: white;
}

.btn-primary:hover {
  background-color: #0056b3;
  transform: translateY(-2px);
}

.btn-secondary {
  background-color: #6c757d;
  color: white;
}

.btn-secondary:hover {
  background-color: #545b62;
  transform: translateY(-2px);
}

.alert-box {
  padding: 15px;
  margin: 15px 0;
  border-radius: 4px;
  font-weight: bold;
}

.alert-success {
  background-color: #d4edda;
  color: #155724;
  border: 1px solid #c3e6cb;
}

.alert-danger {
  background-color: #f8d7da;
  color: #721c24;
  border: 1px solid #f5c6cb;
}

/* 响应式设计 */
@media (max-width: 768px) {
  .card-container {
    padding: 15px;
    margin: 10px 0;
  }
  
  .button-group {
    flex-direction: column;
    align-items: center;
  }
  
  .btn {
    width: 100%;
    max-width: 200px;
  }
}

然后创建 React 组件:

import React, { useState } from 'react';
import './StylesheetExample.css'; // 导入CSS文件

function StylesheetExample() {
  const [message, setMessage] = useState('');
  const [messageType, setMessageType] = useState('');
  const [count, setCount] = useState(0);

  const handlePrimaryClick = () => {
    setCount(count + 1);
    setMessage(`点击了 ${count + 1} 次主按钮`);
    setMessageType('success');
  };

  const handleSecondaryClick = () => {
    setCount(count - 1);
    setMessage(`点击了 ${count - 1} 次次按钮`);
    setMessageType('danger');
  };

  const resetCount = () => {
    setCount(0);
    setMessage('计数器已重置');
    setMessageType('success');
  };

  return (
    <div className="card-container">
      <h2 className="card-title">CSS样式表示例</h2>
      
      <div className="card-content">
        <p>当前计数: <strong>{count}</strong></p>
        
        {/* 条件渲染alert消息 */}
        {message && (
          <div className={`alert-box alert-${messageType}`}>
            {message}
          </div>
        )}
        
        <div className="button-group">
          <button className="btn btn-primary" onClick={handlePrimaryClick}>
            主按钮 (+1)
          </button>
          
          <button className="btn btn-secondary" onClick={handleSecondaryClick}>
            次按钮 (-1)
          </button>
          
          <button className="btn btn-secondary" onClick={resetCount}>
            重置
          </button>
        </div>
      </div>
      
      {/* 条件样式示例 */}
      <div className="card-content">
        <h3>条件样式示例</h3>
        <p>根据计数值改变样式:</p>
        <div 
          className="alert-box" 
          style={{ 
            backgroundColor: count > 0 ? '#d4edda' : count < 0 ? '#f8d7da' : '#fff3cd',
            color: count > 0 ? '#155724' : count < 0 ? '#721c24' : '#856404',
            border: count > 0 ? '1px solid #c3e6cb' : count < 0 ? '1px solid #f5c6cb' : '1px solid #ffeaa7'
          }}
        >
          {count > 0 ? '正数状态' : count < 0 ? '负数状态' : '零状态'}
        </div>
      </div>
    </div>
  );
}

export default StylesheetExample;

案例3:CSS Modules

首先创建 CSSModulesExample.module.css 文件:

/* CSSModulesExample.module.css */
.container {
  padding: 20px;
  background-color: #e9ecef;
  border-radius: 8px;
  margin: 20px 0;
  font-family: 'Arial', sans-serif;
}

.title {
  color: #28a745;
  font-size: 24px;
  margin-bottom: 15px;
  text-align: center;
  border-bottom: 2px solid #28a745;
  padding-bottom: 10px;
}

.contentBox {
  background-color: white;
  padding: 20px;
  border-radius: 6px;
  margin: 15px 0;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

.buttonContainer {
  display: flex;
  justify-content: space-around;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 20px;
}

.primaryBtn {
  padding: 12px 24px;
  background-color: #28a745;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 16px;
  transition: all 0.3s ease;
}

.primaryBtn:hover {
  background-color: #218838;
  transform: scale(1.05);
}

.dangerBtn {
  padding: 12px 24px;
  background-color: #dc3545;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 16px;
  transition: all 0.3s ease;
}

.dangerBtn:hover {
  background-color: #c82333;
  transform: scale(1.05);
}

.infoBox {
  padding: 15px;
  margin: 15px 0;
  border-radius: 4px;
  font-weight: 500;
}

.info {
  composes: infoBox;
  background-color: #cce5ff;
  color: #004085;
  border: 1px solid #b8daff;
}

.warning {
  composes: infoBox;
  background-color: #fff3cd;
  color: #856404;
  border: 1px solid #ffeaa7;
}

.success {
  composes: infoBox;
  background-color: #d4edda;
  color: #155724;
  border: 1px solid #c3e6cb;
}

/* 动画效果 */
@keyframes fadeIn {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

.animatedBox {
  animation: fadeIn 0.5s ease-out;
}

/* 响应式设计 */
@media (max-width: 768px) {
  .container {
    padding: 15px;
    margin: 10px 0;
  }
  
  .buttonContainer {
    flex-direction: column;
    align-items: center;
  }
  
  .primaryBtn, .dangerBtn {
    width: 100%;
    max-width: 250px;
  }
}

然后创建 React 组件:

import React, { useState, useEffect } from 'react';
import styles from './CSSModulesExample.module.css'; // 导入CSS Modules

function CSSModulesExample() {
  const [count, setCount] = useState(0);
  const [showMessage, setShowMessage] = useState(false);
  const [messageType, setMessageType] = useState('info');
  const [isVisible, setIsVisible] = useState(true);

  // 模拟组件加载时的动画效果
  useEffect(() => {
    const timer = setTimeout(() => {
      setShowMessage(true);
    }, 500);
    return () => clearTimeout(timer);
  }, []);

  const increment = () => {
    setCount(count + 1);
    setMessageType('success');
    setShowMessage(true);
    // 3秒后隐藏消息
    setTimeout(() => setShowMessage(false), 3000);
  };

  const decrement = () => {
    setCount(count - 1);
    setMessageType('warning');
    setShowMessage(true);
    setTimeout(() => setShowMessage(false), 3000);
  };

  const reset = () => {
    setCount(0);
    setMessageType('info');
    setShowMessage(true);
    setTimeout(() => setShowMessage(false), 3000);
  };

  const toggleVisibility = () => {
    setIsVisible(!isVisible);
  };

  // 根据计数值动态选择样式
  const getDynamicStyle = () => {
    if (count > 0) return styles.success;
    if (count < 0) return styles.warning;
    return styles.info;
  };

  return (
    <div className={styles.container}>
      <h2 className={styles.title}>CSS Modules 示例</h2>
      
      {/* 可切换可见性的内容框 */}
      {isVisible && (
        <div className={`${styles.contentBox} ${styles.animatedBox}`}>
          <h3>计数器</h3>
          <p>当前值: <strong>{count}</strong></p>
          
          {/* 条件渲染的消息框 */}
          {showMessage && (
            <div className={styles[messageType]}>
              {messageType === 'success' && `增加了1,现在是 ${count}`}
              {messageType === 'warning' && `减少了1,现在是 ${count}`}
              {messageType === 'info' && `已重置为 ${count}`}
            </div>
          )}
          
          <div className={styles.buttonContainer}>
            <button className={styles.primaryBtn} onClick={increment}>
              增加 (+1)
            </button>
            <button className={styles.dangerBtn} onClick={decrement}>
              减少 (-1)
            </button>
            <button className={styles.primaryBtn} onClick={reset}>
              重置
            </button>
          </div>
        </div>
      )}
      
      {/* 动态样式示例 */}
      <div className={styles.contentBox}>
        <h3>动态样式示例</h3>
        <div className={getDynamicStyle()}>
          {count > 0 ? '正数状态 - 成功样式' : 
           count < 0 ? '负数状态 - 警告样式' : 
           '零状态 - 信息样式'}
        </div>
      </div>
      
      {/* 控制组件可见性的按钮 */}
      <div className={styles.buttonContainer}>
        <button 
          className={isVisible ? styles.dangerBtn : styles.primaryBtn}
          onClick={toggleVisibility}
        >
          {isVisible ? '隐藏内容' : '显示内容'}
        </button>
      </div>
    </div>
  );
}

export default CSSModulesExample;

案例4:Styled-components

首先安装 styled-components:

npm install styled-components

然后创建组件:

import React, { useState } from 'react';
import styled, { keyframes, css } from 'styled-components';

// 定义动画
const fadeIn = keyframes`
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
`;

// 定义基础容器样式
const Container = styled.div`
  padding: 20px;
  background-color: ${props => props.theme.backgroundColor || '#f8f9fa'};
  border-radius: 8px;
  margin: 20px 0;
  box-shadow: 0 2px 10px rgba(0,0,0,0.1);
  font-family: 'Arial', sans-serif;
  animation: ${fadeIn} 0.6s ease-out;
`;

// 标题样式
const Title = styled.h2`
  color: ${props => props.theme.titleColor || '#343a40'};
  font-size: 24px;
  margin-bottom: 15px;
  text-align: center;
  border-bottom: 2px solid ${props => props.theme.accentColor || '#007bff'};
  padding-bottom: 10px;
  position: relative;
  
  &::after {
    content: '';
    position: absolute;
    bottom: -2px;
    left: 50%;
    width: 60px;
    height: 2px;
    background-color: ${props => props.theme.accentColor || '#007bff'};
    transform: translateX(-50%);
  }
`;

// 内容框样式
const ContentBox = styled.div`
  background-color: white;
  padding: 20px;
  border-radius: 6px;
  margin: 15px 0;
  box-shadow: 0 2px 8px rgba(0,0,0,0.05);
  transition: all 0.3s ease;
  
  &:hover {
    box-shadow: 0 4px 15px rgba(0,0,0,0.1);
    transform: translateY(-2px);
  }
`;

// 按钮组容器
const ButtonGroup = styled.div`
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 20px;
`;

// 基础按钮样式
const BaseButton = styled.button`
  padding: 12px 24px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 16px;
  font-weight: 500;
  transition: all 0.3s ease;
  position: relative;
  overflow: hidden;
  
  &:before {
    content: '';
    position: absolute;
    top: 0;
    left: -100%;
    width: 100%;
    height: 100%;
    background: rgba(255,255,255,0.2);
    transition: all 0.5s ease;
  }
  
  &:hover:before {
    left: 100%;
  }
  
  &:hover {
    transform: translateY(-2px) scale(1.03);
    box-shadow: 0 4px 15px rgba(0,0,0,0.2);
  }
  
  &:active {
    transform: translateY(0) scale(0.98);
  }
`;

// 主按钮样式 - 扩展BaseButton
const PrimaryButton = styled(BaseButton)`
  background-color: ${props => props.theme.primaryColor || '#007bff'};
  color: white;
  
  &:hover {
    background-color: ${props => props.theme.primaryHoverColor || '#0056b3'};
  }
`;

// 危险按钮样式 - 扩展BaseButton
const DangerButton = styled(BaseButton)`
  background-color: ${props => props.theme.dangerColor || '#dc3545'};
  color: white;
  
  &:hover {
    background-color: ${props => props.theme.dangerHoverColor || '#c82333'};
  }
`;

// 信息框样式 - 根据类型动态变化
const InfoBox = styled.div`
  padding: 15px;
  margin: 15px 0;
  border-radius: 4px;
  font-weight: 500;
  text-align: center;
  animation: ${fadeIn} 0.4s ease-out;
  
  ${props => props.type === 'success' && css`
    background-color: #d4edda;
    color: #155724;
    border: 1px solid #c3e6cb;
    border-left: 5px solid #28a745;
  `}
  
  ${props => props.type === 'warning' && css`
    background-color: #fff3cd;
    color: #856404;
    border: 1px solid #ffeaa7;
    border-left: 5px solid #ffc107;
  `}
  
  ${props => props.type === 'danger' && css`
    background-color: #f8d7da;
    color: #721c24;
    border: 1px solid #f5c6cb;
    border-left: 5px solid #dc3545;
  `}
  
  ${props => props.type === 'info' && css`
    background-color: #cce5ff;
    color: #004085;
    border: 1px solid #b8daff;
    border-left: 5px solid #17a2b8;
  `}
`;

// 主题配置
const theme = {
  backgroundColor: '#f8f9fa',
  titleColor: '#2c3e50',
  accentColor: '#3498db',
  primaryColor: '#3498db',
  primaryHoverColor: '#2980b9',
  dangerColor: '#e74c3c',
  dangerHoverColor: '#c0392b'
};

function StyledComponentsExample() {
  const [count, setCount] = useState(0);
  const [showMessage, setShowMessage] = useState(false);
  const [messageType, setMessageType] = useState('info');
  const [themeMode, setThemeMode] = useState('light');

  // 切换主题
  const toggleTheme = () => {
    setThemeMode(themeMode === 'light' ? 'dark' : 'light');
  };

  // 自定义暗色主题
  const darkTheme = {
    backgroundColor: '#2c3e50',
    titleColor: '#ecf0f1',
    accentColor: '#3498db',
    primaryColor: '#3498db',
    primaryHoverColor: '#2980b9',
    dangerColor: '#e74c3c',
    dangerHoverColor: '#c0392b'
  };

  const currentTheme = themeMode === 'dark' ? darkTheme : theme;

  const increment = () => {
    setCount(count + 1);
    setMessageType('success');
    setShowMessage(true);
    setTimeout(() => setShowMessage(false), 3000);
  };

  const decrement = () => {
    setCount(count - 1);
    setMessageType('warning');
    setShowMessage(true);
    setTimeout(() => setShowMessage(false), 3000);
  };

  const reset = () => {
    setCount(0);
    setMessageType('info');
    setShowMessage(true);
    setTimeout(() => setShowMessage(false), 3000);
  };

  return (
    <Container theme={currentTheme}>
      <Title theme={currentTheme}>
        Styled-components 示例
      </Title>
      
      <ContentBox>
        <h3 style={{ color: currentTheme.titleColor, textAlign: 'center' }}>
          计数器: {count}
        </h3>
        
        {/* 条件渲染的消息框 */}
        {showMessage && (
          <InfoBox type={messageType}>
            {messageType === 'success' && `计数器增加到 ${count}`}
            {messageType === 'warning' && `计数器减少到 ${count}`}
            {messageType === 'info' && `计数器重置为 ${count}`}
          </InfoBox>
        )}
        
        <ButtonGroup>
          <PrimaryButton onClick={increment}>
            增加 (+1)
          </PrimaryButton>
          <DangerButton onClick={decrement}>
            减少 (-1)
          </DangerButton>
          <PrimaryButton onClick={reset}>
            重置
          </PrimaryButton>
        </ButtonGroup>
      </ContentBox>
      
      {/* 主题切换示例 */}
      <ContentBox>
        <h3 style={{ color: currentTheme.titleColor, textAlign: 'center' }}>
          主题: {themeMode === 'light' ? '浅色模式' : '深色模式'}
        </h3>
        <ButtonGroup>
          <PrimaryButton onClick={toggleTheme}>
            切换到 {themeMode === 'light' ? '深色' : '浅色'} 模式
          </PrimaryButton>
        </ButtonGroup>
      </ContentBox>
      
      {/* 动态样式示例 */}
      <ContentBox>
        <h3 style={{ color: currentTheme.titleColor, textAlign: 'center' }}>
          动态样式示例
        </h3>
        <InfoBox 
          type={count > 0 ? 'success' : count < 0 ? 'danger' : 'info'}
        >
          {count > 0 ? '正数 - 成功样式' : 
           count < 0 ? '负数 - 危险样式' : 
           '零 - 信息样式'}
        </InfoBox>
      </ContentBox>
    </Container>
  );
}

// 包装组件以应用主题
const ThemedStyledComponentsExample = () => (
  <StyledComponentsExample />
);

export default ThemedStyledComponentsExample;

案例5:Sass/SCSS 集成

首先安装 node-sass 或 sass:

npm install sass

创建 SassExample.scss 文件:

// SassExample.scss
// 定义变量
$primary-color: #007bff;
$secondary-color: #6c757d;
$success-color: #28a745;
$danger-color: #dc3545;
$warning-color: #ffc107;
$info-color: #17a2b8;

$border-radius: 8px;
$box-shadow: 0 2px 10px rgba(0,0,0,0.1);

// 混合
@mixin button-style($bg-color, $hover-color) {
  padding: 12px 24px;
  background-color: $bg-color;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 16px;
  font-weight: 500;
  transition: all 0.3s ease;
  
  &:hover {
    background-color: $hover-color;
    transform: translateY(-2px) scale(1.03);
    box-shadow: 0 4px 15px rgba(0,0,0,0.2);
  }
  
  &:active {
    transform: translateY(0) scale(0.98);
  }
}

// 容器样式
.sass-container {
  padding: 20px;
  background-color: #f8f9fa;
  border-radius: $border-radius;
  margin: 20px 0;
  box-shadow: $box-shadow;
  font-family: 'Arial', sans-serif;
  
  // 嵌套样式
  .title {
    color: #343a40;
    font-size: 24px;
    margin-bottom: 15px;
    text-align: center;
    border-bottom: 2px solid $primary-color;
    padding-bottom: 10px;
    position: relative;
    
    &::after {
      content: '';
      position: absolute;
      bottom: -2px;
      left: 50%;
      width: 60px;
      height: 2px;
      background-color: $primary-color;
      transform: translateX(-50%);
    }
  }
}

// 内容框
.sass-content-box {
  background-color: white;
  padding: 20px;
  border-radius: 6px;
  margin: 15px 0;
  box-shadow: 0 2px 8px rgba(0,0,0,0.05);
  transition: all 0.3s ease;
  
  &:hover {
    box-shadow: 0 4px 15px rgba(0,0,0,0.1);
    transform: translateY(-2px);
  }
  
  // 嵌套的标题
  h3 {
    color: #343a40;
    text-align: center;
    margin-bottom: 15px;
  }
}

// 按钮组
.sass-button-group {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 20px;
}

// 使用混合定义按钮
.sass-primary-btn {
  @include button-style($primary-color, darken($primary-color, 10%));
}

.sass-success-btn {
  @include button-style($success-color, darken($success-color, 10%));
}

.sass-danger-btn {
  @include button-style($danger-color, darken($danger-color, 10%));
}

.sass-warning-btn {
  @include button-style($warning-color, darken($warning-color, 10%));
  color: #212529; // 警告按钮文字颜色
}

// 信息框
.sass-info-box {
  padding: 15px;
  margin: 15px 0;
  border-radius: 4px;
  font-weight: 500;
  text-align: center;
  
  &.success {
    background-color: lighten($success-color, 40%);
    color: darken($success-color, 20%);
    border: 1px solid lighten($success-color, 30%);
    border-left: 5px solid $success-color;
  }
  
  &.warning {
    background-color: lighten($warning-color, 40%);
    color: darken($warning-color, 20%);
    border: 1px solid lighten($warning-color, 30%);
    border-left: 5px solid $warning-color;
  }
  
  &.danger {
    background-color: lighten($danger-color, 40%);
    color: darken($danger-color, 20%);
    border: 1px solid lighten($danger-color, 30%);
    border-left: 5px solid $danger-color;
  }
  
  &.info {
    background-color: lighten($info-color, 40%);
    color: darken($info-color, 20%);
    border: 1px solid lighten($info-color, 30%);
    border-left: 5px solid $info-color;
  }
}

// 响应式设计
@media (max-width: 768px) {
  .sass-container {
    padding: 15px;
    margin: 10px 0;
  }
  
  .sass-button-group {
    flex-direction: column;
    align-items: center;
  }
  
  .sass-primary-btn, 
  .sass-success-btn, 
  .sass-danger-btn, 
  .sass-warning-btn {
    width: 100%;
    max-width: 250px;
  }
}

// 暗色主题
.dark-theme {
  .sass-container {
    background-color: #2c3e50;
    
    .title {
      color: #ecf0f1;
      border-bottom-color: $info-color;
      
      &::after {
        background-color: $info-color;
      }
    }
  }
  
  .sass-content-box {
    background-color: #34495e;
    
    h3 {
      color: #ecf0f1;
    }
  }
}

创建 React 组件:

import React, { useState } from 'react';
import './SassExample.scss'; // 导入SCSS文件

function SassExample() {
  const [count, setCount] = useState(0);
  const [showMessage, setShowMessage] = useState(false);
  const [messageType, setMessageType] = useState('info');
  const [theme, setTheme] = useState('light');

  const increment = () => {
    setCount(count + 1);
    setMessageType('success');
    setShowMessage(true);
    setTimeout(() => setShowMessage(false), 3000);
  };

  const decrement = () => {
    setCount(count - 1);
    setMessageType('warning');
    setShowMessage(true);
    setTimeout(() => setShowMessage(false), 3000);
  };

  const reset = () => {
    setCount(0);
    setMessageType('info');
    setShowMessage(true);
    setTimeout(() => setShowMessage(false), 3000);
  };

  const toggleTheme = () => {
    setTheme(theme === 'light' ? 'dark' : 'light');
  };

  return (
    <div className={`sass-container ${theme === 'dark' ? 'dark-theme' : ''}`}>
      <h2 className="title">Sass/SCSS 示例</h2>
      
      <div className="sass-content-box">
        <h3>计数器: {count}</h3>
        
        {/* 条件渲染的消息框 */}
        {showMessage && (
          <div className={`sass-info-box ${messageType}`}>
            {messageType === 'success' && `计数器增加到 ${count}`}
            {messageType === 'warning' && `计数器减少到 ${count}`}
            {messageType === 'info' && `计数器重置为 ${count}`}
          </div>
        )}
        
        <div className="sass-button-group">
          <button className="sass-primary-btn" onClick={increment}>
            增加 (+1)
          </button>
          <button className="sass-danger-btn" onClick={decrement}>
            减少 (-1)
          </button>
          <button className="sass-success-btn" onClick={reset}>
            重置
          </button>
        </div>
      </div>
      
      {/* 主题切换 */}
      <div className="sass-content-box">
        <h3>当前主题: {theme === 'light' ? '浅色模式' : '深色模式'}</h3>
        <div className="sass-button-group">
          <button className="sass-warning-btn" onClick={toggleTheme}>
            切换到 {theme === 'light' ? '深色' : '浅色'} 模式
          </button>
        </div>
      </div>
      
      {/* 动态样式示例 */}
      <div className="sass-content-box">
        <h3>动态样式示例</h3>
        <div className={`sass-info-box ${count > 0 ? 'success' : count < 0 ? 'danger' : 'info'}`}>
          {count > 0 ? '正数 - 成功样式' : 
           count < 0 ? '负数 - 危险样式' : 
           '零 - 信息样式'}
        </div>
      </div>
    </div>
  );
}

export default SassExample;

案例6:Tailwind CSS

首先安装 Tailwind CSS:

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

配置 tailwind.config.js

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./src/**/*.{js,jsx,ts,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

src/index.css 中添加:

@tailwind base;
@tailwind components;
@tailwind utilities;

创建组件:

import React, { useState } from 'react';

function TailwindExample() {
  const [count, setCount] = useState(0);
  const [showMessage, setShowMessage] = useState(false);
  const [messageType, setMessageType] = useState('info');
  const [darkMode, setDarkMode] = useState(false);

  const increment = () => {
    setCount(count + 1);
    setMessageType('success');
    setShowMessage(true);
    setTimeout(() => setShowMessage(false), 3000);
  };

  const decrement = () => {
    setCount(count - 1);
    setMessageType('warning');
    setShowMessage(true);
    setTimeout(() => setShowMessage(false), 3000);
  };

  const reset = () => {
    setCount(0);
    setMessageType('info');
    setShowMessage(true);
    setTimeout(() => setShowMessage(false), 3000);
  };

  const toggleDarkMode = () => {
    setDarkMode(!darkMode);
  };

  // 根据消息类型返回相应的Tailwind CSS类
  const getMessageClasses = () => {
    switch (messageType) {
      case 'success':
        return 'bg-green-100 border border-green-400 text-green-700';
      case 'warning':
        return 'bg-yellow-100 border border-yellow-400 text-yellow-700';
      case 'danger':
        return 'bg-red-100 border border-red-400 text-red-700';
      case 'info':
        return 'bg-blue-100 border border-blue-400 text-blue-700';
      default:
        return 'bg-gray-100 border border-gray-400 text-gray-700';
    }
  };

  // 根据计数值返回相应的动态样式
  const getDynamicClasses = () => {
    if (count > 0) return 'bg-green-100 border-l-4 border-green-500 text-green-700';
    if (count < 0) return 'bg-red-100 border-l-4 border-red-500 text-red-700';
    return 'bg-blue-100 border-l-4 border-blue-500 text-blue-700';
  };

  return (
    <div className={`p-6 rounded-lg shadow-lg transition-all duration-300 ${darkMode ? 'bg-gray-800 text-white' : 'bg-gray-100'}`}>
      <h2 className={`text-2xl font-bold mb-4 text-center pb-2 border-b-2 ${darkMode ? 'border-blue-400 text-blue-300' : 'border-blue-500 text-gray-800'}`}>
        Tailwind CSS 示例
      </h2>
      
      <div className={`p-6 rounded-lg shadow-md transition-all duration-300 hover:shadow-lg hover:-translate-y-1 ${darkMode ? 'bg-gray-700' : 'bg-white'}`}>
        <h3 className={`text-xl font-semibold text-center mb-4 ${darkMode ? 'text-white' : 'text-gray-800'}`}>
          计数器: <span className="font-bold">{count}</span>
        </h3>
        
        {/* 条件渲染的消息框 */}
        {showMessage && (
          <div className={`p-4 mb-4 rounded border-l-4 ${getMessageClasses()} animate-fade-in`}>
            <p className="font-medium">
              {messageType === 'success' && `计数器增加到 ${count}`}
              {messageType === 'warning' && `计数器减少到 ${count}`}
              {messageType === 'info' && `计数器重置为 ${count}`}
            </p>
          </div>
        )}
        
        <div className="flex flex-wrap justify-center gap-3 mt-6">
          <button 
            className="px-6 py-3 bg-blue-500 hover:bg-blue-600 text-white font-medium rounded-lg shadow transition-all duration-300 transform hover:scale-105 active:scale-95 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50"
            onClick={increment}
          >
            增加 (+1)
          </button>
          
          <button 
            className="px-6 py-3 bg-red-500 hover:bg-red-600 text-white font-medium rounded-lg shadow transition-all duration-300 transform hover:scale-105 active:scale-95 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-opacity-50"
            onClick={decrement}
          >
            减少 (-1)
          </button>
          
          <button 
            className="px-6 py-3 bg-green-500 hover:bg-green-600 text-white font-medium rounded-lg shadow transition-all duration-300 transform hover:scale-105 active:scale-95 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-opacity-50"
            onClick={reset}
          >
            重置
          </button>
        </div>
      </div>
      
      {/* 主题切换 */}
      <div className={`mt-6 p-6 rounded-lg shadow-md transition-all duration-300 ${darkMode ? 'bg-gray-700' : 'bg-white'}`}>
        <h3 className={`text-xl font-semibold text-center mb-4 ${darkMode ? 'text-white' : 'text-gray-800'}`}>
          当前主题: <span className="font-bold">{darkMode ? '深色模式' : '浅色模式'}</span>
        </h3>
        <div className="flex justify-center">
          <button 
            className={`px-6 py-3 font-medium rounded-lg shadow transition-all duration-300 transform hover:scale-105 active:scale-95 focus:outline-none ${
              darkMode 
                ? 'bg-yellow-500 hover:bg-yellow-600 text-white' 
                : 'bg-gray-800 hover:bg-gray-900 text-white'
            }`}
            onClick={toggleDarkMode}
          >
            切换到 {darkMode ? '浅色' : '深色'} 模式
          </button>
        </div>
      </div>
      
      {/* 动态样式示例 */}
      <div className={`mt-6 p-6 rounded-lg shadow-md transition-all duration-300 ${darkMode ? 'bg-gray-700' : 'bg-white'}`}>
        <h3 className={`text-xl font-semibold text-center mb-4 ${darkMode ? 'text-white' : 'text-gray-800'}`}>
          动态样式示例
        </h3>
        <div className={`p-4 rounded border-l-4 ${getDynamicClasses()}`}>
          <p className="font-medium">
            {count > 0 ? '正数 - 成功样式' : 
             count < 0 ? '负数 - 危险样式' : 
             '零 - 信息样式'}
          </p>
        </div>
      </div>
      
      {/* 响应式设计示例 */}
      <div className={`mt-6 p-6 rounded-lg shadow-md transition-all duration-300 ${darkMode ? 'bg-gray-700' : 'bg-white'}`}>
        <h3 className={`text-xl font-semibold text-center mb-4 ${darkMode ? 'text-white' : 'text-gray-800'}`}>
          响应式设计示例
        </h3>
        <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
          <div className={`p-4 rounded-lg text-center transition-all duration-300 hover:shadow-lg ${darkMode ? 'bg-gray-600 hover:bg-gray-500' : 'bg-blue-50 hover:bg-blue-100'}`}>
            <h4 className="font-bold">移动端</h4>
            <p className="text-sm">单列布局</p>
          </div>
          <div className={`p-4 rounded-lg text-center transition-all duration-300 hover:shadow-lg ${darkMode ? 'bg-gray-600 hover:bg-gray-500' : 'bg-green-50 hover:bg-green-100'}`}>
            <h4 className="font-bold">平板端</h4>
            <p className="text-sm">双列布局</p>
          </div>
          <div className={`p-4 rounded-lg text-center transition-all duration-300 hover:shadow-lg ${darkMode ? 'bg-gray-600 hover:bg-gray-500' : 'bg-purple-50 hover:bg-purple-100'}`}>
            <h4 className="font-bold">桌面端</h4>
            <p className="text-sm">三列布局</p>
          </div>
        </div>
      </div>
    </div>
  );
}

export default TailwindExample;

案例7:综合应用 - 完整的样式实践

import React, { useState, useEffect } from 'react';
import './ComprehensiveExample.css'; // 基础CSS
import styles from './ComprehensiveExample.module.css'; // CSS Modules

// 行内样式对象
const inlineStyles = {
  heroSection: {
    padding: '60px 20px',
    textAlign: 'center',
    background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
    color: 'white',
    borderRadius: '12px',
    margin: '20px 0',
    boxShadow: '0 10px 30px rgba(0,0,0,0.2)'
  },
  cardGrid: {
    display: 'grid',
    gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))',
    gap: '20px',
    marginTop: '30px'
  }
};

function ComprehensiveExample() {
  const [activeTab, setActiveTab] = useState('all');
  const [searchTerm, setSearchTerm] = useState('');
  const [darkMode, setDarkMode] = useState(false);
  const [animatedCards, setAnimatedCards] = useState([]);

  // 模拟数据
  const projects = [
    { id: 1, title: '电商网站', category: 'web', status: 'completed', progress: 100 },
    { id: 2, title: '移动应用', category: 'mobile', status: 'in-progress', progress: 65 },
    { id: 3, title: '数据分析平台', category: 'web', status: 'planning', progress: 20 },
    { id: 4, title: 'AI聊天机器人', category: 'ai', status: 'in-progress', progress: 80 },
    { id: 5, title: '物联网系统', category: 'iot', status: 'completed', progress: 100 },
    { id: 6, title: '区块链应用', category: 'blockchain', status: 'planning', progress: 10 }
  ];

  // 过滤项目
  const filteredProjects = projects.filter(project => {
    const matchesTab = activeTab === 'all' || project.category === activeTab;
    const matchesSearch = project.title.toLowerCase().includes(searchTerm.toLowerCase());
    return matchesTab && matchesSearch;
  });

  // 切换暗色模式
  const toggleDarkMode = () => {
    setDarkMode(!darkMode);
  };

  // 动画效果
  useEffect(() => {
    const timer = setTimeout(() => {
      setAnimatedCards(filteredProjects.map(p => p.id));
    }, 300);
    return () => clearTimeout(timer);
  }, [filteredProjects]);

  // 获取状态相关的样式类
  const getStatusClass = (status) => {
    switch (status) {
      case 'completed': return styles.completed;
      case 'in-progress': return styles.inProgress;
      case 'planning': return styles.planning;
      default: return '';
    }
  };

  // 获取进度条样式
  const getProgressStyle = (progress) => ({
    width: `${progress}%`,
    height: '8px',
    borderRadius: '4px',
    backgroundColor: progress === 100 ? '#28a745' : '#007bff',
    transition: 'width 0.5s ease-in-out'
  });

  return (
    <div className={`${styles.container} ${darkMode ? styles.darkMode : ''}`}>
      {/* 英雄区域 - 行内样式 */}
      <div style={inlineStyles.heroSection}>
        <h1 className={styles.heroTitle}>项目管理系统</h1>
        <p className={styles.heroSubtitle}>管理您的所有项目,跟踪进度,提高效率</p>
        <button 
          className={styles.toggleButton}
          onClick={toggleDarkMode}
          aria-label={darkMode ? '切换到浅色模式' : '切换到深色模式'}
        >
          {darkMode ? '☀️ 浅色模式' : '🌙 深色模式'}
        </button>
      </div>

      {/* 搜索和过滤 - CSS Modules */}
      <div className={styles.controls}>
        <input
          type="text"
          placeholder="搜索项目..."
          value={searchTerm}
          onChange={(e) => setSearchTerm(e.target.value)}
          className={styles.searchInput}
        />
        
        <div className={styles.tabContainer}>
          {['all', 'web', 'mobile', 'ai', 'iot', 'blockchain'].map(tab => (
            <button
              key={tab}
              className={`${styles.tabButton} ${activeTab === tab ? styles.activeTab : ''}`}
              onClick={() => setActiveTab(tab)}
            >
              {tab === 'all' ? '全部' : tab}
            </button>
          ))}
        </div>
      </div>

      {/* 项目卡片网格 - 行内样式 */}
      <div style={inlineStyles.cardGrid}>
        {filteredProjects.length === 0 ? (
          <div className={styles.noResults}>
            <p>没有找到匹配的项目</p>
            <button 
              className={styles.resetButton}
              onClick={() => {
                setSearchTerm('');
                setActiveTab('all');
              }}
            >
              重置筛选条件
            </button>
          </div>
        ) : (
          filteredProjects.map(project => (
            <div
              key={project.id}
              className={`${styles.card} ${animatedCards.includes(project.id) ? styles.animateIn : ''} ${getStatusClass(project.status)}`}
            >
              <div className={styles.cardHeader}>
                <h3 className={styles.cardTitle}>{project.title}</h3>
                <span className={`${styles.statusBadge} ${styles[project.status]}`}>
                  {project.status === 'completed' && '已完成'}
                  {project.status === 'in-progress' && '进行中'}
                  {project.status === 'planning' && '规划中'}
                </span>
              </div>
              
              <div className={styles.cardBody}>
                <p className={styles.category}>
                  <strong>类别:</strong> {project.category}
                </p>
                
                <div className={styles.progressContainer}>
                  <div className={styles.progressLabel}>
                    <span>进度</span>
                    <span>{project.progress}%</span>
                  </div>
                  <div className={styles.progressBarBackground}>
                    <div style={getProgressStyle(project.progress)}></div>
                  </div>
                </div>
              </div>
              
              <div className={styles.cardFooter}>
                <button className={styles.actionButton}>查看详情</button>
                <button className={styles.secondaryButton}>编辑</button>
              </div>
            </div>
          ))
        )}
      </div>

      {/* 统计信息 - CSS */}
      <div className="stats-container">
        <div className="stat-card">
          <h4>总项目数</h4>
          <p className="stat-number">{projects.length}</p>
        </div>
        <div className="stat-card">
          <h4>已完成</h4>
          <p className="stat-number">{projects.filter(p => p.status === 'completed').length}</p>
        </div>
        <div className="stat-card">
          <h4>进行中</h4>
          <p className="stat-number">{projects.filter(p => p.status === 'in-progress').length}</p>
        </div>
        <div className="stat-card">
          <h4>平均进度</h4>
          <p className="stat-number">
            {Math.round(projects.reduce((sum, p) => sum + p.progress, 0) / projects.length)}%
          </p>
        </div>
      </div>
    </div>
  );
}

export default ComprehensiveExample;

对应的 ComprehensiveExample.css

/* ComprehensiveExample.css */
.stats-container {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 20px;
  margin: 40px 0;
}

.stat-card {
  background: white;
  padding: 20px;
  border-radius: 8px;
  text-align: center;
  box-shadow: 0 2px 10px rgba(0,0,0,0.05);
  transition: all 0.3s ease;
}

.stat-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 5px 20px rgba(0,0,0,0.1);
}

.stat-card h4 {
  color: #666;
  font-size: 16px;
  margin-bottom: 10px;
}

.stat-number {
  font-size: 32px;
  font-weight: bold;
  color: #333;
}

/* 响应式设计 */
@media (max-width: 768px) {
  .stats-container {
    grid-template-columns: 1fr;
  }
  
  .stat-card {
    padding: 15px;
  }
  
  .stat-number {
    font-size: 24px;
  }
}

对应的 ComprehensiveExample.module.css

/* ComprehensiveExample.module.css */
.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
  font-family: 'Arial', sans-serif;
}

.container.darkMode {
  background-color: #1a1a1a;
  color: #f0f0f0;
}

.heroTitle {
  font-size: 2.5rem;
  margin: 0 0 15px 0;
  font-weight: 700;
  text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
}

.heroSubtitle {
  font-size: 1.2rem;
  margin: 0 0 30px 0;
  opacity: 0.9;
}

.toggleButton {
  background: rgba(255,255,255,0.2);
  border: 2px solid rgba(255,255,255,0.3);
  color: white;
  padding: 12px 24px;
  border-radius: 30px;
  font-size: 16px;
  cursor: pointer;
  transition: all 0.3s ease;
  backdrop-filter: blur(10px);
}

.toggleButton:hover {
  background: rgba(255,255,255,0.3);
  transform: translateY(-2px);
}

.controls {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  margin: 30px 0;
  padding: 20px;
  background: white;
  border-radius: 12px;
  box-shadow: 0 2px 15px rgba(0,0,0,0.05);
}

.searchInput {
  flex: 1;
  min-width: 250px;
  padding: 12px 16px;
  border: 2px solid #e0e0e0;
  border-radius: 8px;
  font-size: 16px;
  transition: border-color 0.3s ease;
}

.searchInput:focus {
  outline: none;
  border-color: #007bff;
  box-shadow: 0 0 0 3px rgba(0,38,155,0.1);
}

.tabContainer {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.tabButton {
  padding: 8px 16px;
  background: #f0f0f0;
  border: none;
  border-radius: 20px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
  transition: all 0.3s ease;
}

.tabButton:hover {
  background: #e0e0e0;
}

.tabButton.activeTab {
  background: #007bff;
  color: white;
}

.tabButton.activeTab:hover {
  background: #0056b3;
}

.card {
  background: white;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 4px 20px rgba(0,0,0,0.08);
  transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
  opacity: 0;
  transform: translateY(30px);
}

.card.animateIn {
  opacity: 1;
  transform: translateY(0);
}

.card:hover {
  transform: translateY(-10px) scale(1.02);
  box-shadow: 0 10px 30px rgba(0,0,0,0.15);
}

.cardHeader {
  padding: 20px;
  border-bottom: 1px solid #eee;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.cardTitle {
  margin: 0;
  font-size: 1.3rem;
  color: #333;
  font-weight: 600;
}

.statusBadge {
  padding: 6px 12px;
  border-radius: 20px;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.completed {
  background: #d4edda;
  color: #155724;
  border-left: 4px solid #28a745;
}

.inProgress {
  background: #cce5ff;
  color: #004085;
  border-left: 4px solid #007bff;
}

.planning {
  background: #fff3cd;
  color: #856404;
  border-left: 4px solid #ffc107;
}

.cardBody {
  padding: 20px;
}

.category {
  color: #666;
  margin: 0 0 20px 0;
  font-size: 14px;
}

.progressContainer {
  margin: 20px 0;
}

.progressLabel {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
  font-size: 14px;
  color: #555;
}

.progressBarBackground {
  width: 100%;
  height: 8px;
  background: #f0f0f0;
  border-radius: 4px;
  overflow: hidden;
}

.cardFooter {
  padding: 20px;
  display: flex;
  gap: 10px;
  border-top: 1px solid #eee;
}

.actionButton {
  flex: 1;
  padding: 10px;
  background: #007bff;
  color: white;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
  transition: all 0.3s ease;
}

.actionButton:hover {
  background: #0056b3;
  transform: translateY(-2px);
}

.secondaryButton {
  padding: 10px 15px;
  background: #f0f0f0;
  color: #555;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
  transition: all 0.3s ease;
}

.secondaryButton:hover {
  background: #e0e0e0;
  transform: translateY(-2px);
}

.noResults {
  grid-column: 1 / -1;
  text-align: center;
  padding: 60px 20px;
  background: #f8f9fa;
  border-radius: 12px;
  border: 2px dashed #dee2e6;
}

.noResults p {
  font-size: 1.2rem;
  color: #666;
  margin: 0 0 20px 0;
}

.resetButton {
  background: #007bff;
  color: white;
  border: none;
  padding: 12px 24px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 16px;
  font-weight: 500;
  transition: all 0.3s ease;
}

.resetButton:hover {
  background: #0056b3;
  transform: translateY(-2px);
}

/* 暗色模式样式 */
.container.darkMode .controls {
  background: #2a2a2a;
  box-shadow: 0 2px 15px rgba(0,0,0,0.2);
}

.container.darkMode .searchInput {
  background: #333;
  color: #fff;
  border-color: #444;
}

.container.darkMode .searchInput:focus {
  border-color: #007bff;
  box-shadow: 0 0 0 3px rgba(0,123,255,0.2);
}

.container.darkMode .tabButton {
  background: #333;
  color: #ccc;
}

.container.darkMode .tabButton:hover {
  background: #444;
}

.container.darkMode .tabButton.activeTab {
  background: #007bff;
  color: white;
}

.container.darkMode .card {
  background: #2a2a2a;
  box-shadow: 0 4px 20px rgba(0,0,0,0.2);
}

.container.darkMode .cardHeader {
  border-bottom-color: #444;
}

.container.darkMode .cardTitle {
  color: #fff;
}

.container.darkMode .category {
  color: #aaa;
}

.container.darkMode .progressLabel {
  color: #ccc;
}

.container.darkMode .progressBarBackground {
  background: #444;
}

.container.darkMode .cardFooter {
  border-top-color: #444;
}

.container.darkMode .secondaryButton {
  background: #333;
  color: #ccc;
}

.container.darkMode .secondaryButton:hover {
  background: #444;
}

/* 响应式设计 */
@media (max-width: 768px) {
  .container {
    padding: 15px;
  }
  
  .heroTitle {
    font-size: 2rem;
  }
  
  .controls {
    flex-direction: column;
    padding: 15px;
  }
  
  .searchInput {
    min-width: auto;
  }
  
  .tabContainer {
    justify-content: center;
  }
  
  .cardHeader {
    flex-direction: column;
    gap: 10px;
    text-align: center;
  }
  
  .cardFooter {
    flex-direction: column;
  }
  
  .actionButton, .secondaryButton {
    width: 100%;
  }
}

三、总结与最佳实践

1. 选择合适的样式方法

  • 小型项目/组件: 行内样式或CSS样式表
  • 中大型项目: CSS Modules或Styled-components
  • 团队协作: CSS Modules(避免命名冲突)
  • 设计系统: Styled-components(主题支持好)
  • 快速原型: Tailwind CSS

2. 最佳实践

  • 命名规范: 使用有意义的类名,遵循BEM或类似规范
  • 组件化: 每个组件有自己的样式,避免全局污染
  • 性能考虑: 避免过度使用行内样式,特别是大型列表
  • 可维护性: 将样式与逻辑分离,使用CSS变量或主题
  • 响应式设计: 始终考虑不同屏幕尺寸的适配

3. 常见问题解决

  • 样式不生效: 检查className拼写、CSS文件是否正确导入
  • 样式冲突: 使用CSS Modules或更具体的类名
  • 性能问题: 避免在render中创建样式对象,使用useMemo
  • 动态样式: 使用状态管理,避免直接操作DOM

4. 学习建议

  1. 从CSS样式表开始,熟悉基础
  2. 学习CSS Modules,理解局部作用域
  3. 尝试Styled-components,体验CSS-in-JS
  4. 掌握Tailwind CSS,提高开发效率
  5. 学习Sass/SCSS,增强CSS能力

通过以上全面的介绍和详细的案例代码,你应该能够掌握React中各种样式方法的使用。记住,选择适合自己项目和团队的样式方案最重要,不必追求最新最酷的技术,而要注重可维护性和团队协作效率。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐