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 的自定义配置与扩展:
核心要点
- 配置文件:掌握 tailwind.config.js 的结构和用法
- 主题定制:学会自定义颜色、字体、间距、断点等
- 工具类扩展:了解如何添加自定义工具类和组件
- 插件系统:学会使用和创建插件
- 暗色模式:实现完整的暗色模式支持
- 生产优化:掌握构建优化和性能监控
最佳实践
- 保持配置文件的组织性和可维护性
- 遵循设计系统的一致性
- 合理使用插件和扩展
- 注意生产环境的性能优化
- 定期审查和清理不必要的配置
下一步
在下一章中,我们将学习性能优化技巧,了解如何让 Tailwind CSS 项目运行得更快更高效。
9.11 练习题
- 主题定制练习:创建一套完整的品牌色彩系统和字体系统
- 插件开发练习:开发一个自定义插件,添加特定的工具类
- 配置优化练习:优化一个现有项目的 Tailwind 配置,提升构建性能
练习提示
- 从项目需求出发进行配置
- 保持配置的简洁和高效
- 测试配置在不同环境下的表现
- 关注配置对构建时间和文件大小的影响