文档
开发指南UI定制指南

UI定制指南

🚀 5分钟速成 - UI定制核心步骤

# 1. 修改主题色彩 (2分钟)
vim src/styles/globals.css

# 2. 自定义组件样式 (2分钟) 
vim src/modules/ui/button.tsx

# 3. 配置字体和图标 (1分钟)
vim tailwind.config.ts

关键文件快速定位:

  • 🎨 主题配置: src/styles/globals.css - CSS变量定义
  • 🧩 组件样式: src/modules/ui/ - Shadcn组件
  • ⚙️ Tailwind配置: tailwind.config.ts - 设计系统
  • 🖼️ 静态资源: public/ - Logo、图标、图片

5分钟改造效果: 品牌色彩完整替换 + 字体升级 + 核心组件定制

❓ 为什么选择这套UI定制方案

为MVP快速验证:

  • 10分钟品牌化: 从默认主题到品牌定制只需10分钟
  • 🎯 用户认知: 定制UI让产品看起来更专业可信
  • 💰 节省成本: 避免聘请UI设计师,开发者就能搞定
  • 🚀 快速迭代: CSS变量让主题切换毫秒级完成

商业价值体现:

投入: 10分钟定制时间
产出: 品牌专业度提升50% + 用户信任度增加
ROI: 无需设计师成本,开发者独立完成品牌化

🤔 为什么是 Shadcn + Tailwind + CSS变量?

技术选型对比:

方案定制速度学习成本维护难度MVP适合度
Shadcn+Tailwind⚡ 10分钟🟢 低🟢 易⭐⭐⭐⭐⭐
Material-UI🐌 1小时🟡 中🟡 中⭐⭐⭐
Ant Design🐌 2小时🟡 中🔴 难⭐⭐
完全自建🐌 1周🔴 高🔴 难

核心优势:

  • 📱 移动优先: 自带响应式,无需额外配置
  • 无障碍: Radix UI确保可访问性合规
  • 🎨 设计令牌: CSS变量让主题管理系统化
  • 📦 按需导入: 只打包使用的组件,体积最小

🧠 UI定制核心原理

三层架构设计:

🎨 主题层 (CSS变量) → 控制全局色彩、字体、间距
🧩 组件层 (Shadcn) → 可复用的UI组件库  
🎯 业务层 (自定义) → 项目特定的复合组件

设计令牌系统:

:root {
  --primary: 222.2 84% 4.9%;        /* 主色调 */
  --primary-foreground: 210 40% 98%; /* 主色文字 */
  --secondary: 210 40% 96%;          /* 次要色 */
  --accent: 210 40% 96%;             /* 强调色 */
  --border: 214.3 31.8% 91.4%;      /* 边框色 */
  --radius: 0.5rem;                 /* 圆角大小 */
}

响应式断点:

const screens = {
  'sm': '640px',   // 手机横屏
  'md': '768px',   // 平板
  'lg': '1024px',  // 笔记本
  'xl': '1280px',  // 桌面
}

🛠️ 实战:10分钟完成品牌定制

步骤1: 品牌色彩替换 (3分钟)

修改主题配色:

/* src/styles/globals.css */
:root {
  /* 🔵 蓝色科技风 */
  --primary: 214 100% 50%;
  --primary-foreground: 0 0% 100%;
  
  /* 🟢 绿色环保风 */
  --primary: 142 76% 36%;
  --primary-foreground: 0 0% 100%;
  
  /* 🟣 紫色创意风 */
  --primary: 263 70% 50%;
  --primary-foreground: 0 0% 100%;
}

暗色模式适配:

.dark {
  --primary: 214 100% 60%;          /* 暗色模式下调亮 */
  --background: 222.2 84% 4.9%;     /* 深色背景 */
  --foreground: 210 40% 98%;        /* 浅色文字 */
}

步骤2: 字体升级 (2分钟)

配置品牌字体:

// tailwind.config.ts
export default {
  theme: {
    fontFamily: {
      sans: ['Inter', 'system-ui', 'sans-serif'],
      mono: ['JetBrains Mono', 'monospace'],
      brand: ['Poppins', 'sans-serif'],  // 品牌专用字体
    }
  }
}

字体权重映射:

/* 全局字体配置 */
.font-brand { 
  font-family: 'Poppins', sans-serif;
  font-weight: 600;
}

步骤3: 核心组件定制 (3分钟)

Button组件定制:

// src/modules/ui/button.tsx
const buttonVariants = cva(
  "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors",
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground hover:bg-primary/90",
        outline: "border border-input bg-background hover:bg-accent",
        ghost: "hover:bg-accent hover:text-accent-foreground",
        // 🆕 品牌专用变体
        brand: "bg-gradient-to-r from-primary to-blue-600 text-white hover:opacity-90",
        success: "bg-green-600 text-white hover:bg-green-700",
      },
      size: {
        default: "h-10 px-4 py-2",
        sm: "h-9 rounded-md px-3",
        lg: "h-11 rounded-md px-8",
        // 🆕 移动端优化
        touch: "h-12 px-6 text-base", // 44px最小触摸区域
      }
    }
  }
)

使用示例:

<Button variant="brand" size="touch">
  立即开始
</Button>

步骤4: Logo和图标替换 (2分钟)

替换Logo文件:

# 替换默认Logo (SVG格式最佳)
cp your-logo.svg public/logo.svg
cp your-icon.png public/icon.png

Logo组件使用:

// src/modules/shared/logo.tsx
export function Logo({ className }: { className?: string }) {
  return (
    <Image
      src="/logo.svg"
      alt="品牌Logo"
      width={120}
      height={40}
      className={cn("h-8 w-auto", className)}
    />
  )
}

📱 响应式设计实战

移动端优化策略

触摸友好的按钮:

// 最小44px触摸区域
<Button className="min-h-[44px] min-w-[44px] touch-manipulation">
  确认
</Button>

响应式导航:

// 桌面端: 水平导航,移动端: 汉堡菜单
<nav className="hidden md:flex md:space-x-8">
  <Link href="/docs">文档</Link>
  <Link href="/pricing">定价</Link>
</nav>

<Sheet> {/* 移动端抽屉菜单 */}
  <SheetTrigger className="md:hidden">
    <Menu className="h-6 w-6" />
  </SheetTrigger>
</Sheet>

响应式网格布局:

<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
  {features.map(feature => (
    <FeatureCard key={feature.id} {...feature} />
  ))}
</div>

性能优化

图片优化:

import Image from 'next/image'

<Image
  src="/hero-image.webp"
  alt="产品展示"
  width={800}
  height={600}
  priority // 首屏图片优先加载
  placeholder="blur" // 模糊占位符
  className="rounded-lg shadow-lg"
/>

字体优化:

// app/layout.tsx
import { Inter } from 'next/font/google'

const inter = Inter({ 
  subsets: ['latin'],
  display: 'swap', // 字体交换策略
  variable: '--font-inter'
})

🎨 高级定制技巧

1. 动态主题切换

主题上下文:

// src/lib/theme-provider.tsx
export function ThemeProvider({ children }: { children: React.ReactNode }) {
  const [theme, setTheme] = useState<'light' | 'dark' | 'system'>('system')
  
  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  )
}

主题切换组件:

export function ThemeToggle() {
  const { theme, setTheme } = useTheme()
  
  return (
    <Button
      variant="ghost"
      size="sm"
      onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
    >
      {theme === 'dark' ? <Sun /> : <Moon />}
    </Button>
  )
}

2. 动画增强

过渡动画配置:

// tailwind.config.ts
module.exports = {
  theme: {
    extend: {
      animation: {
        'fade-in': 'fadeIn 0.5s ease-in-out',
        'slide-up': 'slideUp 0.3s ease-out',
        'pulse-slow': 'pulse 3s infinite',
      },
      keyframes: {
        fadeIn: {
          '0%': { opacity: '0' },
          '100%': { opacity: '1' },
        },
        slideUp: {
          '0%': { transform: 'translateY(10px)', opacity: '0' },
          '100%': { transform: 'translateY(0)', opacity: '1' },
        }
      }
    }
  }
}

使用动画:

<div className="animate-fade-in">
  <h1 className="animate-slide-up animation-delay-200">欢迎使用</h1>
</div>

3. 自定义组件变体

创建品牌卡片组件:

// src/modules/ui/brand-card.tsx
const cardVariants = cva(
  "rounded-lg border bg-card text-card-foreground shadow-sm",
  {
    variants: {
      variant: {
        default: "border-border",
        highlighted: "border-primary bg-primary/5",
        warning: "border-yellow-200 bg-yellow-50",
      },
      size: {
        sm: "p-4",
        md: "p-6", 
        lg: "p-8",
      }
    },
    defaultVariants: {
      variant: "default",
      size: "md",
    }
  }
)

export function BrandCard({ 
  variant, 
  size, 
  className, 
  children, 
  ...props 
}: BrandCardProps) {
  return (
    <div className={cn(cardVariants({ variant, size }), className)} {...props}>
      {children}
    </div>
  )
}

🛠️ 常见问题解决

问题1: 暗色模式下颜色显示异常

解决方案:

/* 确保暗色模式变量覆盖完整 */
.dark {
  --background: 222.2 84% 4.9%;
  --foreground: 210 40% 98%;
  --primary: 217.2 91.2% 59.8%;
  --primary-foreground: 222.2 84% 4.9%;
  /* 添加所有颜色变量的暗色版本 */
}

问题2: 移动端组件过小难以点击

解决方案:

// 确保最小触摸区域44px
<Button className="min-h-[44px] px-6 touch-manipulation">
  点击按钮
</Button>

问题3: 字体加载闪烁

解决方案:

// 使用font-display: swap
const inter = Inter({ 
  subsets: ['latin'],
  display: 'swap',
  fallback: ['system-ui', 'arial'] // 后备字体
})

问题4: 组件样式覆盖不生效

解决方案:

// 使用 cn 函数确保类名优先级
<Button className={cn("bg-red-500", customClassName)}>
  自定义按钮
</Button>

// 或者使用 !important (谨慎使用)
<Button className="!bg-red-500">
  强制样式
</Button>

📦 UI组件库扩展

创建组件模板

快速生成新组件:

# 使用Shadcn CLI添加新组件
npx shadcn-ui@latest add badge
npx shadcn-ui@latest add separator
npx shadcn-ui@latest add tooltip

自定义组件模板:

// src/modules/ui/feature-card.tsx
interface FeatureCardProps {
  title: string
  description: string
  icon: React.ReactNode
  className?: string
}

export function FeatureCard({ 
  title, 
  description, 
  icon, 
  className 
}: FeatureCardProps) {
  return (
    <BrandCard className={cn("text-center", className)}>
      <div className="mb-4 flex justify-center text-primary">
        {icon}
      </div>
      <h3 className="mb-2 text-lg font-semibold">{title}</h3>
      <p className="text-muted-foreground">{description}</p>
    </BrandCard>
  )
}

组件文档生成

Storybook集成 (可选):

bun add -D @storybook/react @storybook/addon-essentials

内建组件展示页面:

// app/components/page.tsx - 内部组件预览
export default function ComponentsPage() {
  return (
    <div className="container py-8">
      <h1 className="mb-8 text-3xl font-bold">UI组件预览</h1>
      
      <section className="mb-8">
        <h2 className="mb-4 text-xl font-semibold">按钮变体</h2>
        <div className="flex gap-4">
          <Button variant="default">默认</Button>
          <Button variant="brand">品牌</Button>
          <Button variant="outline">轮廓</Button>
        </div>
      </section>
    </div>
  )
}

📎 扩展阅读

设计系统深度学习:

性能优化资源:

设计灵感来源:

工具推荐: