WSの小屋

Tailwind CSS 深入实践:配置体系、主题定制与工程化

引言

Tailwind CSS 在 2024 年发布了 v4 版本,引入了 CSS-first 配置、更快的引擎、更小的运行时,奠定了原子化 CSS 的统治地位。它不再只是一个 CSS 框架,更像一套"基于设计系统的样式工程方法论"。

本文将深入 Tailwind 4 的配置体系、Design Tokens 主题定制、插件开发、与 Vue/React 组件库结合、响应式与暗色模式、性能优化与工程化实践。


一、Tailwind 4 核心变化

1.1 CSS-first 配置

v4 把配置完全放在 CSS 中,告别了 tailwind.config.ts

@import "tailwindcss";

@theme {
  --color-primary: #3b82f6;
  --color-secondary: #10b981;
  --font-family-display: "Inter", sans-serif;
  --breakpoint-sm: 640px;
  --breakpoint-md: 768px;
}

@layer components {
  .btn { @apply px-4 py-2 rounded-md font-medium transition; }
  .btn-primary { @apply btn bg-primary text-white hover:bg-primary/90; }
}

优势:无需 JS 配置文件、所有 token 都是 CSS 变量(便于运行时主题切换)、按需引入。

1.2 引擎提速

Tailwind 4 用 Rust 重写了核心引擎(Oxide):

任务 Tailwind 3 Tailwind 4
首次构建 ~3s ~0.6s
增量构建 ~300ms ~50ms
大型项目 HMR ~500ms ~80ms

二、Design Tokens 主题定制

2.1 颜色系统(OKLCH 色彩空间)

@theme {
  --color-primary: oklch(0.6 0.2 250);
  --color-brand-50: oklch(0.97 0.02 250);
  --color-brand-100: oklch(0.95 0.04 250);
  --color-brand-500: oklch(0.6 0.2 250);
  --color-brand-900: oklch(0.3 0.1 250);
}
<button className="bg-brand-500 hover:bg-brand-600 text-brand-50">Click</button>

2.2 多主题切换

@theme {
  --color-bg: oklch(1 0 0);
  --color-fg: oklch(0.15 0 0);
}
[data-theme="dark"] {
  --color-bg: oklch(0.15 0 0);
  --color-fg: oklch(0.95 0 0);
}
function setTheme(theme: 'light' | 'dark') {
  document.documentElement.dataset.theme = theme
}
// <div className="bg-bg text-fg">主题切换时立即生效</div>

2.3 完整 Design Tokens 示例

@theme {
  --color-primary: #3b82f6;
  --color-primary-foreground: #ffffff;
  --color-muted: #f3f4f6;
  --color-muted-foreground: #6b7280;
  --color-destructive: #ef4444;
  --color-border: #e5e7eb;
  --color-ring: #3b82f6;
  --radius-sm: 0.25rem;
  --radius-md: 0.5rem;
  --radius-lg: 0.75rem;
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
  --shadow-md: 0 4px 6px rgba(0,0,0,0.1);
  --font-family-sans: "Inter", system-ui, sans-serif;
  --font-family-mono: "JetBrains Mono", monospace;
  --duration-fast: 150ms;
  --duration-normal: 250ms;
  --z-dropdown: 1000;
  --z-modal: 1050;
  --z-toast: 1100;
}

三、插件开发

3.1 CSS @utility 自定义原子类

@utility content-auto { content-visibility: auto; }
@utility scrollbar-hidden {
  &::-webkit-scrollbar { display: none; }
  scrollbar-width: none;
}

3.2 JS 插件(通过 @plugin 引入)

@import "tailwindcss";
@plugin "./tailwind-plugin.js";
export default function ({ addUtilities, addVariant }) {
  addUtilities({
    '.text-shadow-sm': { textShadow: '0 1px 2px rgba(0,0,0,0.1)' },
    '.text-shadow-lg': { textShadow: '0 4px 8px rgba(0,0,0,0.2)' },
  })
  addVariant('pointer-coarse', '@media (pointer: coarse)')
  addVariant('rtl', '&:where([dir="rtl"])')
}

四、与 Vue/React 组件库结合

4.1 Vue 组件(reka-ui / shadcn-vue 风格)

<script setup lang="ts">
import { computed } from 'vue'

interface Props {
  variant?: 'default' | 'primary' | 'ghost' | 'destructive'
  size?: 'sm' | 'md' | 'lg'
  disabled?: boolean
}
const props = withDefaults(defineProps<Props>(), { variant: 'default', size: 'md' })

const classes = computed(() => [
  'inline-flex items-center justify-center rounded-md font-medium transition',
  'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
  {
    'bg-primary text-primary-foreground hover:bg-primary/90': props.variant === 'primary',
    'bg-transparent hover:bg-muted': props.variant === 'ghost',
    'bg-destructive text-destructive-foreground hover:bg-destructive/90': props.variant === 'destructive',
  },
  {
    'h-8 px-3 text-sm': props.size === 'sm',
    'h-10 px-4': props.size === 'md',
    'h-12 px-6 text-lg': props.size === 'lg',
  },
  props.disabled && 'opacity-50 cursor-not-allowed',
])
</script>
<template><button :class="classes"><slot /></button></template>

4.2 React + CVA

import { cva, type VariantProps } from 'class-variance-authority'

const button = cva(
  'inline-flex items-center justify-center rounded-md font-medium transition focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-50 disabled:cursor-not-allowed',
  {
    variants: {
      variant: {
        default: 'bg-muted hover:bg-muted/80',
        primary: 'bg-primary text-primary-foreground hover:bg-primary/90',
        ghost: 'bg-transparent hover:bg-muted',
        destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
      },
      size: {
        sm: 'h-8 px-3 text-sm',
        md: 'h-10 px-4',
        lg: 'h-12 px-6 text-lg',
      },
    },
    defaultVariants: { variant: 'default', size: 'md' },
  }
)

export function Button({ className, variant, size, ...props }) {
  return <button className={button({ variant, size, className })} {...props} />
}

五、响应式与暗色模式

5.1 Container Queries

<div className="@container">
  <div className="grid grid-cols-1 @sm:grid-cols-2 @md:grid-cols-3 @lg:grid-cols-4">
    {/* 基于父容器宽度响应 */}
  </div>
</div>

5.2 暗色模式

@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
<div className="bg-white dark:bg-gray-900 dark:text-gray-100">
  {/* 切换 data-theme 即可 */}
</div>

六、性能优化

6.1 CSS 体积控制

@import "tailwindcss/preflight" layer(base);
@import "tailwindcss/utilities";
@source "../src/**/*.{vue,ts,tsx}";

6.2 tailwind-merge 去重

import { twMerge } from 'tailwind-merge'
import { clsx, type ClassValue } from 'clsx'
export const cn = (...inputs: ClassValue[]) => twMerge(clsx(inputs))
// cn('px-4', 'px-6') → 'px-6'

七、工程化最佳实践

7.1 Prettier 排序 class

{ "plugins": ["prettier-plugin-tailwindcss"] }

7.2 ESLint 规则

'tailwindcss/classnames-order': 'warn',
'tailwindcss/no-contradicting-classname': 'error',

7.3 Monorepo 跨包共享设计令牌

packages/
├── design-tokens/
│   ├── src/tokens.css     # 通用 tokens
│   └── src/dark.css       # dark 变体
├── ui/
└── web-app/

八、常见陷阱

动态 class 失效

// ❌ Tailwind 检测不到动态拼接
<button className={`bg-${color}-500`} />

// ✅ 完整 class 映射
const colorMap = { blue: 'bg-blue-500', red: 'bg-red-500' }
<button className={colorMap[color]} />

九、总结

Tailwind 4 的 CSS-first 配置体系让它从"工具类集合"升级为"设计系统工程方法论"。掌握以下要点即可在大型项目中高效使用:CSS-first 配置、设计系统化、组件抽象(cn + cva)、响应式优先(Mobile-first + Container Query)、暗色模式(data-theme 多主题统一管理)、工程化(ESLint + Prettier + Tailwind Merge + VSCode 智能提示)。

Comments | 0条评论