Tailwind CSS v4 核心概念详解
1. Theme(主题系统)
Theme 是 Tailwind CSS 的设计系统核心,定义了所有的设计令牌(Design Tokens)。
1.1 理解 Theme 结构
在 v4 中,theme 通过 CSS 自定义属性(CSS Variables)来定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
/* style.css */ @import "tailwindcss"; @theme { /* 颜色系统 */ --color-primary: #3b82f6; --color-primary-50: #eff6ff; --color-primary-100: #dbeafe; --color-primary-500: #3b82f6; --color-primary-900: #1e3a8a; /* 间距系统 */ --spacing-xs: 0.5rem; --spacing-sm: 0.75rem; --spacing-md: 1rem; --spacing-lg: 1.25rem; --spacing-xl: 1.5rem; /* 字体系统 */ --font-size-xs: 0.75rem; --font-size-sm: 0.875rem; --font-size-base: 1rem; --font-size-lg: 1.125rem; --font-size-xl: 1.25rem; /* 断点系统 */ --breakpoint-sm: 40rem; --breakpoint-md: 48rem; --breakpoint-lg: 64rem; --breakpoint-xl: 80rem; } |
1.2 颜色主题定制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
@theme { /* 品牌色系 */ --color-brand-50: #fef7ff; --color-brand-100: #fdeeff; --color-brand-200: #fbddff; --color-brand-300: #f7bbff; --color-brand-400: #f088ff; --color-brand-500: #e855ff; --color-brand-600: #d333f0; --color-brand-700: #b324d4; --color-brand-800: #931fae; --color-brand-900: #791d8c; /* 语义化颜色 */ --color-success: #10b981; --color-warning: #f59e0b; --color-error: #ef4444; --color-info: #3b82f6; } |
使用自定义颜色:
1 2 3 4 5 6 7 8 |
<div class="bg-brand-500 text-white p-4"> 品牌色背景 </div> <button class="bg-success hover:bg-success/90 text-white px-4 py-2 rounded"> 成功按钮 </button> |
1.3 响应式断点自定义
1 2 3 4 5 6 7 8 9 10 |
@theme { --breakpoint-xs: 20rem; /* 320px */ --breakpoint-sm: 40rem; /* 640px */ --breakpoint-md: 48rem; /* 768px */ --breakpoint-lg: 64rem; /* 1024px */ --breakpoint-xl: 80rem; /* 1280px */ --breakpoint-2xl: 96rem; /* 1536px */ --breakpoint-3xl: 112rem; /* 1792px */ } |
1.4 字体和间距系统
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
@theme { /* 字体族 */ --font-family-sans: "Inter", ui-sans-serif, system-ui; --font-family-serif: "Crimson Text", ui-serif, Georgia; --font-family-mono: "Fira Code", ui-monospace, monospace; /* 字体大小 */ --font-size-2xs: 0.625rem; --font-size-xs: 0.75rem; --font-size-sm: 0.875rem; --font-size-base: 1rem; --font-size-lg: 1.125rem; --font-size-xl: 1.25rem; --font-size-2xl: 1.5rem; --font-size-3xl: 1.875rem; /* 行高 */ --line-height-tight: 1.25; --line-height-normal: 1.5; --line-height-loose: 2; /* 间距比例 */ --spacing-0: 0; --spacing-px: 1px; --spacing-0_5: 0.125rem; --spacing-1: 0.25rem; --spacing-2: 0.5rem; --spacing-3: 0.75rem; --spacing-4: 1rem; --spacing-5: 1.25rem; --spacing-6: 1.5rem; --spacing-8: 2rem; --spacing-10: 2.5rem; --spacing-12: 3rem; --spacing-16: 4rem; --spacing-20: 5rem; --spacing-24: 6rem; --spacing-32: 8rem; } |
2. Layer(层级系统)
Layer 系统控制 CSS 的加载顺序和优先级,确保样式按正确顺序应用。
2.1 Layer 层级结构
1 2 3 |
/* Tailwind v4 的默认层级顺序 */ @layer theme, base, components, utilities; |
2.2 Base Layer(基础层)
用于重置样式和全局基础样式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
@layer base { /* 重置默认样式 */ * { box-sizing: border-box; } html { font-family: theme(fontFamily.sans); line-height: theme(lineHeight.normal); } body { margin: 0; background-color: theme(colors.gray.50); color: theme(colors.gray.900); } /* 全局链接样式 */ a { color: theme(colors.blue.600); text-decoration: none; } a:hover { text-decoration: underline; } /* 标题样式 */ h1, h2, h3, h4, h5, h6 { font-weight: theme(fontWeight.bold); line-height: theme(lineHeight.tight); margin-bottom: theme(spacing.4); } h1 { font-size: theme(fontSize.3xl); } h2 { font-size: theme(fontSize.2xl); } h3 { font-size: theme(fontSize.xl); } /* 表单元素基础样式 */ input, textarea, select { border: 1px solid theme(colors.gray.300); border-radius: theme(borderRadius.md); padding: theme(spacing.2) theme(spacing.3); } input:focus, textarea:focus, select:focus { outline: none; border-color: theme(colors.blue.500); box-shadow: 0 0 0 3px theme(colors.blue.100); } } |
2.3 Components Layer(组件层)
定义可复用的组件样式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
@layer components { /* 按钮组件 */ .btn { display: inline-flex; align-items: center; justify-content: center; padding: theme(spacing.2) theme(spacing.4); border-radius: theme(borderRadius.md); font-weight: theme(fontWeight.medium); transition: all 0.2s; cursor: pointer; border: none; } .btn-primary { background-color: theme(colors.blue.600); color: white; } .btn-primary:hover { background-color: theme(colors.blue.700); } .btn-secondary { background-color: theme(colors.gray.200); color: theme(colors.gray.900); } .btn-secondary:hover { background-color: theme(colors.gray.300); } /* 卡片组件 */ .card { background-color: white; border-radius: theme(borderRadius.lg); box-shadow: theme(boxShadow.md); overflow: hidden; } .card-header { padding: theme(spacing.6); border-bottom: 1px solid theme(colors.gray.200); } .card-body { padding: theme(spacing.6); } .card-footer { padding: theme(spacing.4) theme(spacing.6); background-color: theme(colors.gray.50); border-top: 1px solid theme(colors.gray.200); } /* 表单组件 */ .form-group { margin-bottom: theme(spacing.4); } .form-label { display: block; font-weight: theme(fontWeight.medium); color: theme(colors.gray.700); margin-bottom: theme(spacing.2); } .form-input { display: block; width: 100%; padding: theme(spacing.3); border: 1px solid theme(colors.gray.300); border-radius: theme(borderRadius.md); font-size: theme(fontSize.sm); } .form-input:focus { outline: none; border-color: theme(colors.blue.500); box-shadow: 0 0 0 3px theme(colors.blue.100); } /* 导航组件 */ .nav { display: flex; list-style: none; padding: 0; margin: 0; } .nav-item { margin-right: theme(spacing.6); } .nav-link { color: theme(colors.gray.600); font-weight: theme(fontWeight.medium); padding: theme(spacing.2) 0; border-bottom: 2px solid transparent; transition: all 0.2s; } .nav-link:hover { color: theme(colors.blue.600); border-bottom-color: theme(colors.blue.600); } .nav-link.active { color: theme(colors.blue.600); border-bottom-color: theme(colors.blue.600); } } |
2.4 Utilities Layer(工具层)
定义单一用途的工具类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
@layer utilities { /* 文本截断工具 */ .text-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .text-truncate-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } .text-truncate-3 { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; } /* 滚动条样式 */ .scrollbar-thin { scrollbar-width: thin; scrollbar-color: theme(colors.gray.400) theme(colors.gray.200); } .scrollbar-thin::-webkit-scrollbar { width: 6px; height: 6px; } .scrollbar-thin::-webkit-scrollbar-track { background: theme(colors.gray.200); } .scrollbar-thin::-webkit-scrollbar-thumb { background: theme(colors.gray.400); border-radius: 3px; } /* 玻璃态效果 */ .glass { background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); border: 1px solid rgba(255, 255, 255, 0.2); } /* 渐变工具 */ .gradient-primary { background: linear-gradient(135deg, theme(colors.blue.600), theme(colors.purple.600)); } .gradient-secondary { background: linear-gradient(135deg, theme(colors.gray.600), theme(colors.gray.800)); } /* 动画工具 */ .animate-fade-in { animation: fadeIn 0.5s ease-in-out; } .animate-slide-up { animation: slideUp 0.3s ease-out; } .animate-bounce-in { animation: bounceIn 0.6s ease-out; } /* 响应式工具 */ .aspect-video { aspect-ratio: 16 / 9; } .aspect-square { aspect-ratio: 1 / 1; } /* 交互状态工具 */ .interactive { cursor: pointer; transition: all 0.2s ease; } .interactive:hover { transform: translateY(-2px); box-shadow: theme(boxShadow.lg); } .interactive:active { transform: translateY(0); box-shadow: theme(boxShadow.md); } } /* 动画关键帧 */ @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes slideUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } @keyframes bounceIn { 0% { opacity: 0; transform: scale(0.3); } 50% { opacity: 1; transform: scale(1.05); } 70% { transform: scale(0.9); } 100% { opacity: 1; transform: scale(1); } } |
3. Components(组件系统)
组件是预定义的样式组合,提供一致的 UI 元素。
3.1 按钮组件系统
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
@layer components { /* 基础按钮 */ .btn { @apply inline-flex items-center justify-center px-4 py-2 rounded-md font-medium transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2; } /* 按钮尺寸变体 */ .btn-xs { @apply px-2 py-1 text-xs; } .btn-sm { @apply px-3 py-1.5 text-sm; } .btn-md { @apply px-4 py-2 text-sm; } .btn-lg { @apply px-6 py-3 text-base; } .btn-xl { @apply px-8 py-4 text-lg; } /* 按钮颜色变体 */ .btn-primary { @apply bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500; } .btn-secondary { @apply bg-gray-200 text-gray-900 hover:bg-gray-300 focus:ring-gray-500; } .btn-success { @apply bg-green-600 text-white hover:bg-green-700 focus:ring-green-500; } .btn-danger { @apply bg-red-600 text-white hover:bg-red-700 focus:ring-red-500; } /* 按钮状态变体 */ .btn-outline { @apply bg-transparent border-2; } .btn-outline.btn-primary { @apply border-blue-600 text-blue-600 hover:bg-blue-600 hover:text-white; } .btn-ghost { @apply bg-transparent hover:bg-gray-100; } .btn-disabled { @apply opacity-50 cursor-not-allowed pointer-events-none; } } |
3.2 表单组件系统
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
@layer components { /* 表单组 */ .form-group { @apply mb-4; } /* 标签 */ .form-label { @apply block text-sm font-medium text-gray-700 mb-2; } .form-label.required::after { content: "*"; @apply text-red-500 ml-1; } /* 输入框 */ .form-input { @apply block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500; } .form-input.error { @apply border-red-500 focus:ring-red-500 focus:border-red-500; } .form-input.success { @apply border-green-500 focus:ring-green-500 focus:border-green-500; } /* 文本域 */ .form-textarea { @apply form-input resize-vertical min-h-[100px]; } /* 选择框 */ .form-select { @apply form-input pr-10 bg-white cursor-pointer; background-image: 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"); background-position: right 0.5rem center; background-repeat: no-repeat; background-size: 1.5em 1.5em; } /* 复选框和单选框 */ .form-checkbox, .form-radio { @apply h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded; } .form-radio { @apply rounded-full; } /* 错误消息 */ .form-error { @apply text-sm text-red-600 mt-1; } /* 帮助文本 */ .form-help { @apply text-sm text-gray-500 mt-1; } } |
3.3 卡片组件系统
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
@layer components { /* 基础卡片 */ .card { @apply bg-white rounded-lg shadow-md overflow-hidden; } .card-hover { @apply card hover:shadow-lg transition-shadow duration-200; } /* 卡片内容区域 */ .card-header { @apply px-6 py-4 border-b border-gray-200; } .card-body { @apply px-6 py-4; } .card-footer { @apply px-6 py-4 bg-gray-50 border-t border-gray-200; } /* 卡片标题 */ .card-title { @apply text-lg font-semibold text-gray-900 mb-2; } .card-subtitle { @apply text-sm text-gray-600 mb-4; } /* 卡片变体 */ .card-bordered { @apply border border-gray-200 shadow-sm; } .card-elevated { @apply shadow-lg; } .card-flat { @apply shadow-none border border-gray-200; } } |
4. Utilities(工具类系统)
工具类是单一用途的原子类,可以组合使用。
4.1 间距工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
@layer utilities { /* 自定义间距工具 */ .space-y-0\.5 > * + * { margin-top: 0.125rem; } .space-y-1\.5 > * + * { margin-top: 0.375rem; } .space-y-2\.5 > * + * { margin-top: 0.625rem; } .space-y-3\.5 > * + * { margin-top: 0.875rem; } .space-x-0\.5 > * + * { margin-left: 0.125rem; } .space-x-1\.5 > * + * { margin-left: 0.375rem; } .space-x-2\.5 > * + * { margin-left: 0.625rem; } .space-x-3\.5 > * + * { margin-left: 0.875rem; } /* 安全区域工具 */ .pt-safe { padding-top: env(safe-area-inset-top); } .pb-safe { padding-bottom: env(safe-area-inset-bottom); } .pl-safe { padding-left: env(safe-area-inset-left); } .pr-safe { padding-right: env(safe-area-inset-right); } } |
4.2 文本工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
@layer utilities { /* 文本平衡 */ .text-balance { text-wrap: balance; } /* 文本美化 */ .text-pretty { text-wrap: pretty; } /* 文本选择 */ .select-none { user-select: none; } .select-text { user-select: text; } .select-all { user-select: all; } .select-auto { user-select: auto; } /* 文本方向 */ .writing-vertical-rl { writing-mode: vertical-rl; } .writing-vertical-lr { writing-mode: vertical-lr; } .writing-horizontal-tb { writing-mode: horizontal-tb; } /* 字体特性 */ .font-variant-numeric-tabular { font-variant-numeric: tabular-nums; } .font-variant-numeric-proportional { font-variant-numeric: proportional-nums; } } |
4.3 布局工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
@layer utilities { /* 容器查询 */ .container-xs { container-type: inline-size; } .container-sm { container-type: inline-size; } .container-md { container-type: inline-size; } .container-lg { container-type: inline-size; } /* 逻辑属性 */ .ms-auto { margin-inline-start: auto; } .me-auto { margin-inline-end: auto; } .ps-4 { padding-inline-start: 1rem; } .pe-4 { padding-inline-end: 1rem; } /* 现代布局 */ .stack > * + * { margin-block-start: var(--stack-space, 1rem); } .cluster { display: flex; flex-wrap: wrap; gap: var(--cluster-space, 1rem); } .switcher { display: flex; flex-wrap: wrap; gap: var(--switcher-space, 1rem); } /* Grid 子网格 */ .subgrid { grid-template-columns: subgrid; } .subgrid-rows { grid-template-rows: subgrid; } } |
5. 实际应用示例
5.1 完整的主题配置示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
/* styles.css */ @import "tailwindcss"; @theme { /* 颜色系统 */ --color-primary-50: #f0f9ff; --color-primary-500: #3b82f6; --color-primary-900: #1e3a8a; /* 自定义断点 */ --breakpoint-xs: 20rem; --breakpoint-3xl: 112rem; /* 自定义间距 */ --spacing-18: 4.5rem; --spacing-22: 5.5rem; } @layer base { html { font-family: 'Inter', sans-serif; scroll-behavior: smooth; } body { @apply bg-gray-50 text-gray-900 antialiased; } } @layer components { .page-container { @apply max-w-7xl mx-auto px-4 sm:px-6 lg:px-8; } .section { @apply py-16 lg:py-20; } .heading-1 { @apply text-4xl lg:text-5xl font-bold text-gray-900 mb-4; } .heading-2 { @apply text-3xl lg:text-4xl font-bold text-gray-900 mb-4; } } @layer utilities { .debug-grid { background-image: linear-gradient(rgba(255, 0, 0, 0.1) 1px, transparent 1px), linear-gradient(90deg, rgba(255, 0, 0, 0.1) 1px, transparent 1px); background-size: 20px 20px; } .animate-float { animation: float 3s ease-in-out infinite; } } @keyframes float { 0%, 100% { transform: translateY(0px); } 50% { transform: translateY(-10px); } } |
5.2 组件使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Theme & Layer 示例</title> <link rel="stylesheet" href="styles.css"> </head> <body> <!-- 使用主题色和组件类 --> <header class="bg-white shadow-sm"> <div class="page-container"> <nav class="nav py-4"> <a href="#" class="nav-link active">首页</a> <a href="#" class="nav-link">关于</a> <a href="#" class="nav-link">服务</a> <a href="#" class="nav-link">联系</a> </nav> </div> </header> <main> <section class="section"> <div class="page-container"> <h1 class="heading-1">主题配置示例</h1> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mt-8"> <div class="card card-hover"> <div class="card-header"> <h3 class="card-title">Theme 主题</h3> </div> <div class="card-body"> <p>自定义设计令牌和颜色系统</p> </div> <div class="card-footer"> <button class="btn btn-primary">了解更多</button> </div> </div> <div class="card card-hover"> <div class="card-header"> <h3 class="card-title">Layer 层级</h3> </div> <div class="card-body"> <p>控制样式优先级和加载顺序</p> </div> <div class="card-footer"> <button class="btn btn-secondary">查看详情</button> </div> </div> <div class="card card-hover"> <div class="card-header"> <h3 class="card-title">Components 组件</h3> </div> <div class="card-body"> <p>可复用的 UI 组件样式</p> </div> <div class="card-footer"> <button class="btn btn-success">开始使用</button> </div> </div> </div> <!-- 表单示例 --> <div class="mt-16 max-w-md mx-auto"> <form class="space-y-4"> <div class="form-group"> <label class="form-label required">邮箱地址</label> <input type="email" class="form-input" placeholder="请输入邮箱"> </div> <div class="form-group"> <label class="form-label">消息内容</label> <textarea class="form-textarea" placeholder="请输入消息内容"></textarea> </div> <button type="submit" class="btn btn-primary w-full">提交表单</button> </form> </div> </div> </section> </main> </body> </html> |