9.1 Tailwind CSS 配置概述

9.1.1 配置文件介绍

Tailwind CSS 通过 tailwind.config.js 文件进行配置,这个文件允许你:

  • 自定义设计系统(颜色、字体、间距等)
  • 添加新的工具类
  • 配置构建选项
  • 启用或禁用功能
  • 添加插件

9.1.2 生成配置文件

# 生成基础配置文件
npx tailwindcss init

# 生成完整配置文件(包含所有默认值)
npx tailwindcss init --full

# 同时生成 PostCSS 配置
npx tailwindcss init -p

9.1.3 基础配置结构

// tailwind.config.js
module.exports = {
  content: [
    "./src/**/*.{html,js,ts,jsx,tsx}",
    "./pages/**/*.{html,js,ts,jsx,tsx}",
    "./components/**/*.{html,js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {
      // 扩展默认主题
    },
  },
  plugins: [
    // 添加插件
  ],
  darkMode: 'class', // 或 'media'
  corePlugins: {
    // 启用/禁用核心插件
  },
  variants: {
    // 配置变体(已弃用,使用 JIT 模式)
  },
}

9.2 内容配置

9.2.1 配置内容路径

// tailwind.config.js
module.exports = {
  content: [
    // HTML 文件
    "./src/**/*.html",
    "./public/**/*.html",
    
    // JavaScript 文件
    "./src/**/*.{js,jsx}",
    "./components/**/*.{js,jsx}",
    
    // TypeScript 文件
    "./src/**/*.{ts,tsx}",
    
    // Vue 文件
    "./src/**/*.vue",
    
    // Svelte 文件
    "./src/**/*.svelte",
    
    // PHP 文件
    "./templates/**/*.php",
    
    // 其他模板文件
    "./src/**/*.{erb,haml,slim}",
  ],
  // ...
}

9.2.2 动态类名处理

// 确保动态类名被包含
const colors = ['red', 'green', 'blue'];
const sizes = ['sm', 'md', 'lg'];

// 在代码中使用完整类名
colors.forEach(color => {
  // 好的做法:使用完整类名
  element.className = `bg-${color}-500 text-white`;
  
  // 避免的做法:动态拼接可能导致类名丢失
  // element.className = `bg-${color}-500`; // 如果 color 来自 API
});

// 在配置文件中添加安全列表
module.exports = {
  content: [
    "./src/**/*.{html,js}",
  ],
  safelist: [
    'bg-red-500',
    'bg-green-500',
    'bg-blue-500',
    // 或使用模式
    {
      pattern: /bg-(red|green|blue)-(100|200|300|400|500|600|700|800|900)/,
    },
  ],
  // ...
}

9.3 主题配置

9.3.1 颜色系统自定义

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      colors: {
        // 添加自定义颜色
        'brand': {
          50: '#eff6ff',
          100: '#dbeafe',
          200: '#bfdbfe',
          300: '#93c5fd',
          400: '#60a5fa',
          500: '#3b82f6',
          600: '#2563eb',
          700: '#1d4ed8',
          800: '#1e40af',
          900: '#1e3a8a',
        },
        
        // 简单颜色定义
        'primary': '#3b82f6',
        'secondary': '#64748b',
        'accent': '#f59e0b',
        'danger': '#ef4444',
        'success': '#10b981',
        'warning': '#f59e0b',
        'info': '#3b82f6',
        
        // 使用 CSS 变量
        'custom': {
          'light': 'var(--color-custom-light)',
          'dark': 'var(--color-custom-dark)',
        },
        
        // 覆盖默认颜色
        gray: {
          50: '#f8fafc',
          100: '#f1f5f9',
          200: '#e2e8f0',
          300: '#cbd5e1',
          400: '#94a3b8',
          500: '#64748b',
          600: '#475569',
          700: '#334155',
          800: '#1e293b',
          900: '#0f172a',
        },
      },
    },
  },
}

9.3.2 字体系统自定义

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      fontFamily: {
        // 添加自定义字体
        'sans': ['Inter', 'system-ui', 'sans-serif'],
        'serif': ['Georgia', 'serif'],
        'mono': ['Fira Code', 'monospace'],
        'display': ['Oswald', 'sans-serif'],
        'body': ['Open Sans', 'sans-serif'],
        
        // 中文字体
        'chinese': ['PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'sans-serif'],
      },
      
      fontSize: {
        // 自定义字体大小
        'xs': ['0.75rem', { lineHeight: '1rem' }],
        'sm': ['0.875rem', { lineHeight: '1.25rem' }],
        'base': ['1rem', { lineHeight: '1.5rem' }],
        'lg': ['1.125rem', { lineHeight: '1.75rem' }],
        'xl': ['1.25rem', { lineHeight: '1.75rem' }],
        '2xl': ['1.5rem', { lineHeight: '2rem' }],
        '3xl': ['1.875rem', { lineHeight: '2.25rem' }],
        '4xl': ['2.25rem', { lineHeight: '2.5rem' }],
        '5xl': ['3rem', { lineHeight: '1' }],
        '6xl': ['3.75rem', { lineHeight: '1' }],
        '7xl': ['4.5rem', { lineHeight: '1' }],
        '8xl': ['6rem', { lineHeight: '1' }],
        '9xl': ['8rem', { lineHeight: '1' }],
        
        // 带行高和字间距的复杂定义
        'title': ['2rem', {
          lineHeight: '2.5rem',
          letterSpacing: '-0.01em',
          fontWeight: '700',
        }],
      },
      
      fontWeight: {
        'hairline': 100,
        'thin': 200,
        'light': 300,
        'normal': 400,
        'medium': 500,
        'semibold': 600,
        'bold': 700,
        'extrabold': 800,
        'black': 900,
      },
    },
  },
}

9.3.3 间距系统自定义

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      spacing: {
        // 添加自定义间距
        '72': '18rem',
        '84': '21rem',
        '96': '24rem',
        '128': '32rem',
        
        // 小数间距
        '0.5': '0.125rem',
        '1.5': '0.375rem',
        '2.5': '0.625rem',
        '3.5': '0.875rem',
        
        // 百分比间距
        '1/7': '14.2857143%',
        '2/7': '28.5714286%',
        '3/7': '42.8571429%',
        '4/7': '57.1428571%',
        '5/7': '71.4285714%',
        '6/7': '85.7142857%',
        
        // 视口单位
        'screen': '100vh',
        'screen-1/2': '50vh',
        'screen-1/3': '33.333333vh',
        'screen-2/3': '66.666667vh',
      },
      
      // 最大宽度
      maxWidth: {
        '8xl': '88rem',
        '9xl': '96rem',
        'screen-2xl': '1536px',
      },
      
      // 最小高度
      minHeight: {
        '0': '0',
        '1/4': '25%',
        '1/2': '50%',
        '3/4': '75%',
        'full': '100%',
        'screen': '100vh',
      },
    },
  },
}

9.3.4 断点自定义

// tailwind.config.js
module.exports = {
  theme: {
    screens: {
      // 完全自定义断点
      'xs': '475px',
      'sm': '640px',
      'md': '768px',
      'lg': '1024px',
      'xl': '1280px',
      '2xl': '1536px',
      
      // 添加额外断点
      '3xl': '1600px',
      '4xl': '1920px',
      
      // 自定义断点名称
      'tablet': '640px',
      'laptop': '1024px',
      'desktop': '1280px',
      
      // 范围断点
      'sm-only': {'min': '640px', 'max': '767px'},
      'md-only': {'min': '768px', 'max': '1023px'},
      
      // 最大宽度断点
      'max-sm': {'max': '639px'},
      'max-md': {'max': '767px'},
      'max-lg': {'max': '1023px'},
      
      // 高度断点
      'tall': {'raw': '(min-height: 800px)'},
      'short': {'raw': '(max-height: 600px)'},
      
      // 打印媒体
      'print': {'raw': 'print'},
    },
  },
}

9.4 添加自定义工具类

9.4.1 使用 addUtilities

// tailwind.config.js
const plugin = require('tailwindcss/plugin')

module.exports = {
  // ...
  plugins: [
    plugin(function({ addUtilities, theme, variants }) {
      const newUtilities = {
        // 文本渐变
        '.text-gradient': {
          'background': 'linear-gradient(45deg, #f59e0b, #ef4444)',
          '-webkit-background-clip': 'text',
          '-webkit-text-fill-color': 'transparent',
          'background-clip': 'text',
        },
        
        // 玻璃态效果
        '.glass': {
          'background': 'rgba(255, 255, 255, 0.1)',
          'backdrop-filter': 'blur(10px)',
          'border': '1px solid rgba(255, 255, 255, 0.2)',
        },
        
        // 新拟态效果
        '.neumorphism': {
          'background': '#e0e0e0',
          'border-radius': '20px',
          'box-shadow': '20px 20px 60px #bebebe, -20px -20px 60px #ffffff',
        },
        
        // 滚动条样式
        '.scrollbar-hide': {
          '-ms-overflow-style': 'none',
          'scrollbar-width': 'none',
          '&::-webkit-scrollbar': {
            display: 'none',
          },
        },
        
        '.scrollbar-thin': {
          '&::-webkit-scrollbar': {
            width: '6px',
          },
          '&::-webkit-scrollbar-track': {
            background: '#f1f1f1',
          },
          '&::-webkit-scrollbar-thumb': {
            background: '#c1c1c1',
            'border-radius': '3px',
          },
          '&::-webkit-scrollbar-thumb:hover': {
            background: '#a8a8a8',
          },
        },
        
        // 文本省略
        '.text-ellipsis-2': {
          'display': '-webkit-box',
          '-webkit-line-clamp': '2',
          '-webkit-box-orient': 'vertical',
          'overflow': 'hidden',
        },
        
        '.text-ellipsis-3': {
          'display': '-webkit-box',
          '-webkit-line-clamp': '3',
          '-webkit-box-orient': 'vertical',
          'overflow': 'hidden',
        },
        
        // 居中布局
        '.center': {
          'display': 'flex',
          'align-items': 'center',
          'justify-content': 'center',
        },
        
        '.center-x': {
          'display': 'flex',
          'justify-content': 'center',
        },
        
        '.center-y': {
          'display': 'flex',
          'align-items': 'center',
        },
      }
      
      addUtilities(newUtilities, ['responsive', 'hover'])
    }),
  ],
}

9.4.2 动态工具类

// tailwind.config.js
const plugin = require('tailwindcss/plugin')

module.exports = {
  plugins: [
    plugin(function({ addUtilities, theme }) {
      // 动态生成间距工具类
      const spacingUtilities = {}
      const spacing = theme('spacing')
      
      Object.keys(spacing).forEach(key => {
        spacingUtilities[`.gap-x-${key}`] = {
          'column-gap': spacing[key],
        }
        spacingUtilities[`.gap-y-${key}`] = {
          'row-gap': spacing[key],
        }
      })
      
      // 动态生成颜色工具类
      const colorUtilities = {}
      const colors = theme('colors')
      
      Object.keys(colors).forEach(colorName => {
        if (typeof colors[colorName] === 'object') {
          Object.keys(colors[colorName]).forEach(shade => {
            colorUtilities[`.border-t-${colorName}-${shade}`] = {
              'border-top-color': colors[colorName][shade],
            }
            colorUtilities[`.border-r-${colorName}-${shade}`] = {
              'border-right-color': colors[colorName][shade],
            }
            colorUtilities[`.border-b-${colorName}-${shade}`] = {
              'border-bottom-color': colors[colorName][shade],
            }
            colorUtilities[`.border-l-${colorName}-${shade}`] = {
              'border-left-color': colors[colorName][shade],
            }
          })
        }
      })
      
      addUtilities({
        ...spacingUtilities,
        ...colorUtilities,
      })
    }),
  ],
}

9.5 添加自定义组件

9.5.1 使用 addComponents

// tailwind.config.js
const plugin = require('tailwindcss/plugin')

module.exports = {
  plugins: [
    plugin(function({ addComponents, theme }) {
      addComponents({
        // 按钮组件
        '.btn': {
          padding: `${theme('spacing.2')} ${theme('spacing.4')}`,
          borderRadius: theme('borderRadius.md'),
          fontWeight: theme('fontWeight.medium'),
          fontSize: theme('fontSize.sm'),
          lineHeight: theme('lineHeight.5'),
          transition: 'all 0.2s ease-in-out',
          cursor: 'pointer',
          display: 'inline-flex',
          alignItems: 'center',
          justifyContent: 'center',
          border: '1px solid transparent',
          
          '&:focus': {
            outline: 'none',
            boxShadow: `0 0 0 3px ${theme('colors.blue.500')}40`,
          },
          
          '&:disabled': {
            opacity: '0.5',
            cursor: 'not-allowed',
          },
        },
        
        '.btn-primary': {
          backgroundColor: theme('colors.blue.500'),
          color: theme('colors.white'),
          
          '&:hover': {
            backgroundColor: theme('colors.blue.600'),
          },
          
          '&:active': {
            backgroundColor: theme('colors.blue.700'),
          },
        },
        
        '.btn-secondary': {
          backgroundColor: theme('colors.gray.200'),
          color: theme('colors.gray.900'),
          
          '&:hover': {
            backgroundColor: theme('colors.gray.300'),
          },
        },
        
        '.btn-outline': {
          backgroundColor: 'transparent',
          borderColor: theme('colors.gray.300'),
          color: theme('colors.gray.700'),
          
          '&:hover': {
            backgroundColor: theme('colors.gray.50'),
            borderColor: theme('colors.gray.400'),
          },
        },
        
        '.btn-sm': {
          padding: `${theme('spacing.1')} ${theme('spacing.3')}`,
          fontSize: theme('fontSize.xs'),
        },
        
        '.btn-lg': {
          padding: `${theme('spacing.3')} ${theme('spacing.6')}`,
          fontSize: theme('fontSize.base'),
        },
        
        // 卡片组件
        '.card': {
          backgroundColor: theme('colors.white'),
          borderRadius: theme('borderRadius.lg'),
          boxShadow: theme('boxShadow.md'),
          overflow: 'hidden',
        },
        
        '.card-header': {
          padding: theme('spacing.6'),
          borderBottom: `1px solid ${theme('colors.gray.200')}`,
        },
        
        '.card-body': {
          padding: theme('spacing.6'),
        },
        
        '.card-footer': {
          padding: theme('spacing.6'),
          borderTop: `1px solid ${theme('colors.gray.200')}`,
          backgroundColor: theme('colors.gray.50'),
        },
        
        // 表单组件
        '.form-input': {
          appearance: 'none',
          backgroundColor: theme('colors.white'),
          borderColor: theme('colors.gray.300'),
          borderWidth: '1px',
          borderRadius: theme('borderRadius.md'),
          padding: `${theme('spacing.2')} ${theme('spacing.3')}`,
          fontSize: theme('fontSize.sm'),
          lineHeight: theme('lineHeight.5'),
          width: '100%',
          
          '&:focus': {
            outline: 'none',
            borderColor: theme('colors.blue.500'),
            boxShadow: `0 0 0 3px ${theme('colors.blue.500')}20`,
          },
          
          '&::placeholder': {
            color: theme('colors.gray.400'),
          },
        },
        
        '.form-select': {
          appearance: 'none',
          backgroundColor: theme('colors.white'),
          borderColor: theme('colors.gray.300'),
          borderWidth: '1px',
          borderRadius: theme('borderRadius.md'),
          padding: `${theme('spacing.2')} ${theme('spacing.8')} ${theme('spacing.2')} ${theme('spacing.3')}`,
          fontSize: theme('fontSize.sm'),
          lineHeight: theme('lineHeight.5'),
          width: '100%',
          backgroundImage: `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e")`,
          backgroundPosition: 'right 0.5rem center',
          backgroundRepeat: 'no-repeat',
          backgroundSize: '1.5em 1.5em',
          
          '&:focus': {
            outline: 'none',
            borderColor: theme('colors.blue.500'),
            boxShadow: `0 0 0 3px ${theme('colors.blue.500')}20`,
          },
        },
      })
    }),
  ],
}

9.5.2 响应式组件

// tailwind.config.js
const plugin = require('tailwindcss/plugin')

module.exports = {
  plugins: [
    plugin(function({ addComponents, theme }) {
      addComponents({
        // 响应式容器
        '.container-fluid': {
          width: '100%',
          paddingLeft: theme('spacing.4'),
          paddingRight: theme('spacing.4'),
          marginLeft: 'auto',
          marginRight: 'auto',
          
          [`@media (min-width: ${theme('screens.sm')})`]: {
            paddingLeft: theme('spacing.6'),
            paddingRight: theme('spacing.6'),
          },
          
          [`@media (min-width: ${theme('screens.lg')})`]: {
            paddingLeft: theme('spacing.8'),
            paddingRight: theme('spacing.8'),
          },
        },
        
        // 响应式网格
        '.grid-responsive': {
          display: 'grid',
          gridTemplateColumns: 'repeat(1, minmax(0, 1fr))',
          gap: theme('spacing.4'),
          
          [`@media (min-width: ${theme('screens.sm')})`]: {
            gridTemplateColumns: 'repeat(2, minmax(0, 1fr))',
          },
          
          [`@media (min-width: ${theme('screens.md')})`]: {
            gridTemplateColumns: 'repeat(3, minmax(0, 1fr))',
          },
          
          [`@media (min-width: ${theme('screens.lg')})`]: {
            gridTemplateColumns: 'repeat(4, minmax(0, 1fr))',
          },
        },
      })
    }),
  ],
}

9.6 插件系统

9.6.1 官方插件

# 安装官方插件
npm install @tailwindcss/forms
npm install @tailwindcss/typography
npm install @tailwindcss/aspect-ratio
npm install @tailwindcss/line-clamp
npm install @tailwindcss/container-queries
// tailwind.config.js
module.exports = {
  plugins: [
    // 表单插件
    require('@tailwindcss/forms'),
    
    // 排版插件
    require('@tailwindcss/typography'),
    
    // 宽高比插件
    require('@tailwindcss/aspect-ratio'),
    
    // 行截断插件
    require('@tailwindcss/line-clamp'),
    
    // 容器查询插件
    require('@tailwindcss/container-queries'),
  ],
}

9.6.2 第三方插件

# 安装第三方插件
npm install tailwindcss-animate
npm install @tailwindcss/ui
npm install tailwind-scrollbar
npm install tailwindcss-textshadow
// tailwind.config.js
module.exports = {
  plugins: [
    // 动画插件
    require('tailwindcss-animate'),
    
    // 滚动条插件
    require('tailwind-scrollbar'),
    
    // 文字阴影插件
    require('tailwindcss-textshadow'),
  ],
}

9.6.3 创建自定义插件

// plugins/custom-plugin.js
const plugin = require('tailwindcss/plugin')

module.exports = plugin(function({ addUtilities, addComponents, addBase, theme, variants }) {
  // 添加基础样式
  addBase({
    'h1, h2, h3, h4, h5, h6': {
      fontWeight: theme('fontWeight.bold'),
    },
    'a': {
      color: theme('colors.blue.500'),
      textDecoration: 'underline',
      
      '&:hover': {
        color: theme('colors.blue.600'),
      },
    },
  })
  
  // 添加组件
  addComponents({
    '.alert': {
      padding: theme('spacing.4'),
      borderRadius: theme('borderRadius.md'),
      border: '1px solid',
      
      '&.alert-info': {
        backgroundColor: theme('colors.blue.50'),
        borderColor: theme('colors.blue.200'),
        color: theme('colors.blue.800'),
      },
      
      '&.alert-success': {
        backgroundColor: theme('colors.green.50'),
        borderColor: theme('colors.green.200'),
        color: theme('colors.green.800'),
      },
      
      '&.alert-warning': {
        backgroundColor: theme('colors.yellow.50'),
        borderColor: theme('colors.yellow.200'),
        color: theme('colors.yellow.800'),
      },
      
      '&.alert-error': {
        backgroundColor: theme('colors.red.50'),
        borderColor: theme('colors.red.200'),
        color: theme('colors.red.800'),
      },
    },
  })
  
  // 添加工具类
  addUtilities({
    '.rotate-y-180': {
      transform: 'rotateY(180deg)',
    },
    '.preserve-3d': {
      transformStyle: 'preserve-3d',
    },
    '.perspective': {
      perspective: '1000px',
    },
    '.backface-hidden': {
      backfaceVisibility: 'hidden',
    },
  })
}, {
  theme: {
    extend: {
      // 插件特定的主题扩展
      animation: {
        'flip': 'flip 0.6s ease-in-out',
      },
      keyframes: {
        flip: {
          '0%': { transform: 'rotateY(0deg)' },
          '100%': { transform: 'rotateY(180deg)' },
        },
      },
    },
  },
})

// 在 tailwind.config.js 中使用
module.exports = {
  plugins: [
    require('./plugins/custom-plugin'),
  ],
}

9.7 暗色模式配置

9.7.1 启用暗色模式

// tailwind.config.js
module.exports = {
  darkMode: 'class', // 或 'media'
  // ...
}

9.7.2 暗色模式样式

<!-- 类模式切换 -->
<html class="dark">
  <body class="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
    <div class="bg-gray-100 dark:bg-gray-800 p-4 rounded">
      <h1 class="text-2xl font-bold text-gray-900 dark:text-white">
        暗色模式标题
      </h1>
      <p class="text-gray-600 dark:text-gray-300">
        这是暗色模式下的文本内容。
      </p>
      <button class="bg-blue-500 hover:bg-blue-600 dark:bg-blue-600 dark:hover:bg-blue-700 text-white px-4 py-2 rounded">
        按钮
      </button>
    </div>
  </body>
</html>

9.7.3 暗色模式切换

// 暗色模式切换脚本
function toggleDarkMode() {
  const html = document.documentElement;
  const isDark = html.classList.contains('dark');
  
  if (isDark) {
    html.classList.remove('dark');
    localStorage.setItem('theme', 'light');
  } else {
    html.classList.add('dark');
    localStorage.setItem('theme', 'dark');
  }
}

// 初始化主题
function initTheme() {
  const savedTheme = localStorage.getItem('theme');
  const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
  
  if (savedTheme === 'dark' || (!savedTheme && prefersDark)) {
    document.documentElement.classList.add('dark');
  }
}

// 页面加载时初始化
initTheme();

// 监听系统主题变化
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
  if (!localStorage.getItem('theme')) {
    if (e.matches) {
      document.documentElement.classList.add('dark');
    } else {
      document.documentElement.classList.remove('dark');
    }
  }
});
<!-- 暗色模式切换按钮 -->
<button 
  onclick="toggleDarkMode()" 
  class="p-2 rounded-lg bg-gray-200 dark:bg-gray-700 text-gray-800 dark:text-gray-200 hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors"
>
  <svg class="w-5 h-5 hidden dark:block" fill="currentColor" viewBox="0 0 20 20">
    <path fill-rule="evenodd" d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" clip-rule="evenodd"></path>
  </svg>
  <svg class="w-5 h-5 block dark:hidden" fill="currentColor" viewBox="0 0 20 20">
    <path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path>
  </svg>
</button>

9.8 生产环境优化

9.8.1 PurgeCSS 配置

// tailwind.config.js
module.exports = {
  content: [
    './src/**/*.{html,js,ts,jsx,tsx}',
    './pages/**/*.{html,js,ts,jsx,tsx}',
    './components/**/*.{html,js,ts,jsx,tsx}',
  ],
  
  // 安全列表 - 防止重要类被清除
  safelist: [
    'bg-red-500',
    'text-3xl',
    'lg:text-4xl',
    // 动态类名模式
    {
      pattern: /bg-(red|green|blue)-(100|200|300|400|500|600|700|800|900)/,
      variants: ['lg', 'hover', 'focus', 'lg:hover'],
    },
  ],
  
  // 阻止列表 - 强制清除某些类
  blocklist: [
    'container',
    'collapsible',
  ],
}

9.8.2 构建优化

// postcss.config.js
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
    ...(process.env.NODE_ENV === 'production' ? {
      cssnano: {
        preset: 'default',
      },
    } : {}),
  },
}
// package.json
{
  "scripts": {
    "build-css": "tailwindcss -i ./src/input.css -o ./dist/output.css --watch",
    "build-css-prod": "tailwindcss -i ./src/input.css -o ./dist/output.css --minify"
  }
}

9.8.3 性能监控

// 分析 CSS 文件大小
const fs = require('fs')
const path = require('path')

function analyzeCSSSize() {
  const cssPath = path.join(__dirname, 'dist/output.css')
  const stats = fs.statSync(cssPath)
  const fileSizeInBytes = stats.size
  const fileSizeInKB = fileSizeInBytes / 1024
  
  console.log(`CSS file size: ${fileSizeInKB.toFixed(2)} KB`)
  
  if (fileSizeInKB > 100) {
    console.warn('Warning: CSS file is larger than 100KB')
  }
}

analyzeCSSSize()

9.9 实践案例:完整配置示例

9.9.1 企业级配置

// tailwind.config.js
const defaultTheme = require('tailwindcss/defaultTheme')
const colors = require('tailwindcss/colors')
const plugin = require('tailwindcss/plugin')

module.exports = {
  content: [
    './src/**/*.{html,js,ts,jsx,tsx,vue}',
    './pages/**/*.{html,js,ts,jsx,tsx,vue}',
    './components/**/*.{html,js,ts,jsx,tsx,vue}',
    './layouts/**/*.{html,js,ts,jsx,tsx,vue}',
    './plugins/**/*.{js,ts}',
    './nuxt.config.{js,ts}',
    './app.vue',
  ],
  
  darkMode: 'class',
  
  theme: {
    extend: {
      // 品牌颜色
      colors: {
        primary: {
          50: '#eff6ff',
          100: '#dbeafe',
          200: '#bfdbfe',
          300: '#93c5fd',
          400: '#60a5fa',
          500: '#3b82f6',
          600: '#2563eb',
          700: '#1d4ed8',
          800: '#1e40af',
          900: '#1e3a8a',
        },
        secondary: colors.gray,
        success: colors.green,
        warning: colors.yellow,
        danger: colors.red,
        info: colors.blue,
      },
      
      // 字体系统
      fontFamily: {
        sans: ['Inter', ...defaultTheme.fontFamily.sans],
        mono: ['Fira Code', ...defaultTheme.fontFamily.mono],
        display: ['Oswald', ...defaultTheme.fontFamily.sans],
      },
      
      // 字体大小
      fontSize: {
        'xs': ['0.75rem', { lineHeight: '1rem' }],
        'sm': ['0.875rem', { lineHeight: '1.25rem' }],
        'base': ['1rem', { lineHeight: '1.5rem' }],
        'lg': ['1.125rem', { lineHeight: '1.75rem' }],
        'xl': ['1.25rem', { lineHeight: '1.75rem' }],
        '2xl': ['1.5rem', { lineHeight: '2rem' }],
        '3xl': ['1.875rem', { lineHeight: '2.25rem' }],
        '4xl': ['2.25rem', { lineHeight: '2.5rem' }],
        '5xl': ['3rem', { lineHeight: '1' }],
        '6xl': ['3.75rem', { lineHeight: '1' }],
        '7xl': ['4.5rem', { lineHeight: '1' }],
        '8xl': ['6rem', { lineHeight: '1' }],
        '9xl': ['8rem', { lineHeight: '1' }],
      },
      
      // 间距系统
      spacing: {
        '18': '4.5rem',
        '88': '22rem',
        '128': '32rem',
        '144': '36rem',
      },
      
      // 断点
      screens: {
        'xs': '475px',
        ...defaultTheme.screens,
        '3xl': '1600px',
      },
      
      // 动画
      animation: {
        'fade-in': 'fadeIn 0.5s ease-in-out',
        'slide-up': 'slideUp 0.3s ease-out',
        'slide-down': 'slideDown 0.3s ease-out',
        'scale-in': 'scaleIn 0.2s ease-out',
        'spin-slow': 'spin 3s linear infinite',
      },
      
      keyframes: {
        fadeIn: {
          '0%': { opacity: '0' },
          '100%': { opacity: '1' },
        },
        slideUp: {
          '0%': { transform: 'translateY(10px)', opacity: '0' },
          '100%': { transform: 'translateY(0)', opacity: '1' },
        },
        slideDown: {
          '0%': { transform: 'translateY(-10px)', opacity: '0' },
          '100%': { transform: 'translateY(0)', opacity: '1' },
        },
        scaleIn: {
          '0%': { transform: 'scale(0.9)', opacity: '0' },
          '100%': { transform: 'scale(1)', opacity: '1' },
        },
      },
      
      // 阴影
      boxShadow: {
        'inner-lg': 'inset 0 10px 15px -3px rgba(0, 0, 0, 0.1)',
        'colored': '0 10px 15px -3px rgba(59, 130, 246, 0.4)',
      },
      
      // 背景图片
      backgroundImage: {
        'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
        'gradient-conic': 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
      },
    },
  },
  
  plugins: [
    // 官方插件
    require('@tailwindcss/forms'),
    require('@tailwindcss/typography'),
    require('@tailwindcss/aspect-ratio'),
    
    // 自定义插件
    plugin(function({ addUtilities, addComponents, theme }) {
      // 工具类
      addUtilities({
        '.text-gradient': {
          'background': 'linear-gradient(45deg, #f59e0b, #ef4444)',
          '-webkit-background-clip': 'text',
          '-webkit-text-fill-color': 'transparent',
          'background-clip': 'text',
        },
        '.glass': {
          'background': 'rgba(255, 255, 255, 0.1)',
          'backdrop-filter': 'blur(10px)',
          'border': '1px solid rgba(255, 255, 255, 0.2)',
        },
        '.scrollbar-hide': {
          '-ms-overflow-style': 'none',
          'scrollbar-width': 'none',
          '&::-webkit-scrollbar': {
            display: 'none',
          },
        },
      })
      
      // 组件
      addComponents({
        '.btn': {
          padding: `${theme('spacing.2')} ${theme('spacing.4')}`,
          borderRadius: theme('borderRadius.md'),
          fontWeight: theme('fontWeight.medium'),
          fontSize: theme('fontSize.sm'),
          transition: 'all 0.2s ease-in-out',
          cursor: 'pointer',
          display: 'inline-flex',
          alignItems: 'center',
          justifyContent: 'center',
          
          '&:focus': {
            outline: 'none',
            boxShadow: `0 0 0 3px ${theme('colors.primary.500')}40`,
          },
        },
        
        '.btn-primary': {
          backgroundColor: theme('colors.primary.500'),
          color: theme('colors.white'),
          
          '&:hover': {
            backgroundColor: theme('colors.primary.600'),
          },
        },
        
        '.card': {
          backgroundColor: theme('colors.white'),
          borderRadius: theme('borderRadius.lg'),
          boxShadow: theme('boxShadow.md'),
          overflow: 'hidden',
        },
      })
    }),
  ],
  
  // 核心插件配置
  corePlugins: {
    // 禁用不需要的插件以减小文件大小
    // container: false,
  },
}

9.9.2 配置文件组织

// config/colors.js
module.exports = {
  primary: {
    50: '#eff6ff',
    100: '#dbeafe',
    200: '#bfdbfe',
    300: '#93c5fd',
    400: '#60a5fa',
    500: '#3b82f6',
    600: '#2563eb',
    700: '#1d4ed8',
    800: '#1e40af',
    900: '#1e3a8a',
  },
  // ... 其他颜色
}

// config/typography.js
const defaultTheme = require('tailwindcss/defaultTheme')

module.exports = {
  fontFamily: {
    sans: ['Inter', ...defaultTheme.fontFamily.sans],
    mono: ['Fira Code', ...defaultTheme.fontFamily.mono],
  },
  fontSize: {
    // ... 字体大小配置
  },
}

// config/animations.js
module.exports = {
  animation: {
    'fade-in': 'fadeIn 0.5s ease-in-out',
    'slide-up': 'slideUp 0.3s ease-out',
  },
  keyframes: {
    fadeIn: {
      '0%': { opacity: '0' },
      '100%': { opacity: '1' },
    },
    slideUp: {
      '0%': { transform: 'translateY(10px)', opacity: '0' },
      '100%': { transform: 'translateY(0)', opacity: '1' },
    },
  },
}

// tailwind.config.js
const colors = require('./config/colors')
const typography = require('./config/typography')
const animations = require('./config/animations')

module.exports = {
  // ...
  theme: {
    extend: {
      colors,
      ...typography,
      ...animations,
    },
  },
  // ...
}

9.10 本章总结

在本章中,我们深入学习了 Tailwind CSS 的自定义配置与扩展:

核心要点

  1. 配置文件:掌握 tailwind.config.js 的结构和用法
  2. 主题定制:学会自定义颜色、字体、间距、断点等
  3. 工具类扩展:了解如何添加自定义工具类和组件
  4. 插件系统:学会使用和创建插件
  5. 暗色模式:实现完整的暗色模式支持
  6. 生产优化:掌握构建优化和性能监控

最佳实践

  • 保持配置文件的组织性和可维护性
  • 遵循设计系统的一致性
  • 合理使用插件和扩展
  • 注意生产环境的性能优化
  • 定期审查和清理不必要的配置

下一步

在下一章中,我们将学习性能优化技巧,了解如何让 Tailwind CSS 项目运行得更快更高效。

9.11 练习题

  1. 主题定制练习:创建一套完整的品牌色彩系统和字体系统
  2. 插件开发练习:开发一个自定义插件,添加特定的工具类
  3. 配置优化练习:优化一个现有项目的 Tailwind 配置,提升构建性能

练习提示

  • 从项目需求出发进行配置
  • 保持配置的简洁和高效
  • 测试配置在不同环境下的表现
  • 关注配置对构建时间和文件大小的影响