关于 v0
面向 Web 应用设计与开发的指南型技能,涵盖界面视觉、组件组织、Tailwind CSS、无障碍与性能实践。适合需要一致设计规范和实现建议的 Web 项目。
主要功能
- 01色彩与排版规范
- 02布局和响应式设计指导
- 03组件架构与代码组织
- 04Tailwind CSS 模式
- 05无障碍与性能实践
适用场景
- 01规划 Web 应用界面
- 02组织可复用 UI 组件
- 03检查响应式和无障碍设计
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ headline-design/ design-craft --skill v0安装后在 Claude Code 中输入/v0确认已加载。
附带文件README.md
详细介绍
v0 设计与开发技能
创建专业级、视觉出众且拥有卓越 UI/UX 的 Web 应用的完整指南。
目录
设计理念
核心原则
- 克制胜于堆砌 — 优秀的设计重在删去什么,而非添加什么
- 清晰胜于巧妙 — 用户应该能够立即理解界面
- 一致胜于新奇 — 可预测的模式可以降低认知负担
- 目的胜于装饰 — 每个元素都必须有存在的理由
- 交付有趣的作品,绝不交付丑陋的作品 — 在创意与精致之间取得平衡
v0 美学
- 简洁、现代的界面,留白充足
- 微妙的阴影和边框,营造层次感而不分散注意力
- 流畅且目的明确的动画,引导注意力
- 协调统一、观感专业的配色方案
- 层级清晰的排版
配色系统
3–5 色规则
始终将颜色总数严格控制在 3–5 种。 这一限制有助于保持整体协调。
必需结构
1 Primary Brand Color → CTAs, key actions, brand identity
2-3 Neutrals → Backgrounds, text, borders
1-2 Accent Colors → Status indicators, highlights, secondary actions
颜色选择指南
| 用途 | 建议 |
|---|---|
| 主要操作 | 高饱和度且无障碍易用的品牌色 |
| 背景 | 米白色、柔和的灰色(大面积区域绝不使用纯白) |
| 文本 | 接近黑色(#0a0a0a 至 #1a1a1a),而非纯黑色 |
| 边框/分隔线 | 极浅的灰色(透明度 10-20%) |
| 成功状态 | 青绿色系中的绿色 |
| 错误状态 | 暖红色,避免过于刺眼 |
| 警告状态 | 琥珀色/橙色调 |
色温规则
- 应 使用类似色:蓝色→青色、紫色→粉色、橙色→红色
- 不应 混用色温相反的颜色:粉色→绿色、橙色→蓝色、红色→青色
渐变规则
- 除非明确要求,否则应避免使用渐变 — 纯色更简洁
- 如果必须使用渐变:
- 仅用作微妙的点缀,绝不用在主要元素上
- 颜色节点最多 2–3 个
- 仅使用类似色
- 考虑渐变方向(通常为自上而下或对角线)
设计令牌结构
始终在 CSS 变量中使用语义化设计令牌:
:root {
/* Backgrounds */
--background: 0 0% 100%;
--foreground: 0 0% 3.9%;
/* Cards & Surfaces */
--card: 0 0% 100%;
--card-foreground: 0 0% 3.9%;
/* Primary Actions */
--primary: 0 0% 9%;
--primary-foreground: 0 0% 98%;
/* Secondary Actions */
--secondary: 0 0% 96.1%;
--secondary-foreground: 0 0% 9%;
/* Muted Elements */
--muted: 0 0% 96.1%;
--muted-foreground: 0 0% 45.1%;
/* Accents */
--accent: 0 0% 96.1%;
--accent-foreground: 0 0% 9%;
/* Destructive Actions */
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
/* Borders & Inputs */
--border: 0 0% 89.8%;
--input: 0 0% 89.8%;
--ring: 0 0% 3.9%;
/* Radius */
--radius: 0.5rem;
}
重要规则: 绝不要直接使用 text-white、bg-black 这类颜色。所有内容都必须通过令牌进行主题化。
排版
字体最多 2 种规则
始终将字体系列限制在最多 2 种。 字体过多会造成视觉混乱。
字体搭配策略
Headings: Display or Sans-serif with personality (multiple weights)
Body: Highly readable sans-serif or serif
推荐搭配
| 风格 | 标题 | 正文 |
|---|---|---|
| 现代科技 | Inter、Geist | Inter、Geist |
| 编辑风格 | Playfair Display | Source Sans Pro |
| 初创企业 | Cal Sans、Manrope | Inter |
| 企业风格 | Outfit | System UI |
| 创意风格 | Space Grotesk | DM Sans |
排版比例
使用一致的比例,确保层级清晰:
/* Recommended Tailwind Classes */
text-xs → 12px → Fine print, labels
text-sm → 14px → Secondary text, captions
text-base → 16px → Body text (minimum for readability)
text-lg → 18px → Lead paragraphs
text-xl → 20px → Section headers
text-2xl → 24px → Card titles
text-3xl → 30px → Page sections
text-4xl → 36px → Hero subheadings
text-5xl → 48px → Hero headings
text-6xl+ → 60px+ → Display headings (use sparingly)
行高规则
- 正文文本:
leading-relaxed(1.625),或leading-6至leading-7 - 标题:
leading-tight(1.25)或leading-snug(1.375) - 正文文本绝不要使用默认行高 — 这会过于紧凑
文本换行
- 为标题添加
text-balance,以优化换行效果 - 对重要文案使用
text-pretty - 设置
max-w-prose或max-w-2xl,确保行长易于阅读
在 Next.js 中实现字体
// layout.tsx
import { Inter, Playfair_Display } from 'next/font/google'
const inter = Inter({
subsets: ['latin'],
variable: '--font-sans'
})
const playfair = Playfair_Display({
subsets: ['latin'],
variable: '--font-serif'
})
export default function RootLayout({ children }) {
return (
<html className={`${inter.variable} ${playfair.variable}`}>
<body className="font-sans">{children}</body>
</html>
)
}
// tailwind.config.js
module.exports = {
theme: {
extend: {
fontFamily: {
sans: ['var(--font-sans)'],
serif: ['var(--font-serif)'],
},
},
},
}
布局与间距
移动优先设计
始终先设计移动端,再针对更大的屏幕进行增强。
// ✅ Mobile-first approach
<div className="px-4 md:px-6 lg:px-8">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
// ❌ Desktop-first (avoid)
<div className="px-8 md:px-6 sm:px-4">
布局方法优先级
布局决策遵循以下优先级:
- Flexbox — 适用于大多数布局(导航栏、卡片、简单网格)
- CSS Grid — 适用于复杂的二维布局、便当网格、仪表板
- 绝对定位 — 仅在必要时使用(模态框、工具提示)
- 切勿使用浮动
间距比例
统一使用 Tailwind 的间距比例:
4px = p-1 → Tiny gaps (icon padding)
8px = p-2 → Small gaps (button padding)
12px = p-3 → Compact spacing
16px = p-4 → Standard spacing (most common)
24px = p-6 → Comfortable spacing
32px = p-8 → Section spacing
48px = p-12 → Large section gaps
64px = p-16 → Hero spacing
96px = p-24 → Major section dividers
间距规则
// ✅ Use gap for flex/grid spacing
<div className="flex gap-4">
<div className="grid gap-6">
// ✅ Use padding for container spacing
<section className="px-4 py-12 md:px-6 lg:py-24">
// ❌ Avoid space-* utilities
<div className="space-y-4"> // Less flexible
// ❌ Never mix gap and margin on same element
<div className="flex gap-4 mb-4"> // Pick one approach
容器模式
// Standard content container
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
// Narrow content (articles, forms)
<div className="mx-auto max-w-2xl px-4">
// Full-bleed with contained content
<section className="w-full bg-muted">
<div className="mx-auto max-w-7xl px-4 py-16">
响应式断点
sm: 640px → Large phones, small tablets
md: 768px → Tablets
lg: 1024px → Small laptops, tablets landscape
xl: 1280px → Desktops
2xl: 1536px → Large desktops
组件架构
文件结构
components/
├── ui/ # Base shadcn components (don't modify)
│ ├── button.tsx
│ ├── card.tsx
│ └── ...
├── [feature]/ # Feature-specific components
│ ├── feature-header.tsx
│ ├── feature-card.tsx
│ └── feature-list.tsx
├── layout/ # Layout components
│ ├── header.tsx
│ ├── footer.tsx
│ └── sidebar.tsx
└── shared/ # Shared/common components
├── logo.tsx
├── theme-toggle.tsx
└── loading-state.tsx
组件设计原则
- 单一职责 — 每个组件都做好一件事
- 组合优于配置 — 用简单部分构建复杂 UI
- 使用 Props 进行自定义 — 使用 props,而不是硬编码值
- 合理的默认值 — 开箱即用,并在需要时支持自定义
组件模板
import { cn } from "@/lib/utils"
interface FeatureCardProps {
title: string
description: string
icon?: React.ReactNode
className?: string
variant?: "default" | "highlighted"
}
export function FeatureCard({
title,
description,
icon,
className,
variant = "default"
}: FeatureCardProps) {
return (
<div
className={cn(
"rounded-lg border p-6 transition-colors",
variant === "default" && "bg-card hover:bg-accent",
variant === "highlighted" && "bg-primary text-primary-foreground",
className
)}
>
{icon && (
<div className="mb-4 text-muted-foreground">
{icon}
</div>
)}
<h3 className="font-semibold text-lg">{title}</h3>
<p className="mt-2 text-sm text-muted-foreground">
{description}
</p>
</div>
)
}
页面结构
// app/feature/page.tsx
import { FeatureHero } from "@/components/feature/feature-hero"
import { FeatureGrid } from "@/components/feature/feature-grid"
import { FeatureCTA } from "@/components/feature/feature-cta"
export default function FeaturePage() {
return (
<main>
<FeatureHero />
<FeatureGrid />
<FeatureCTA />
</main>
)
}
切勿创建臃肿的页面文件。 应拆分为逻辑清晰的组件。
Tailwind CSS 模式
类名组织
统一类名顺序:
className={cn(
// 1. Layout (display, position, sizing)
"flex items-center justify-between",
"relative w-full max-w-md",
// 2. Spacing (margin, padding, gap)
"p-4 gap-2",
// 3. Typography
"text-sm font-medium",
// 4. Colors & Backgrounds
"bg-background text-foreground",
// 5. Borders & Shadows
"rounded-lg border shadow-sm",
// 6. Transitions & Animations
"transition-colors duration-200",
// 7. States (hover, focus, active)
"hover:bg-accent focus:ring-2",
// 8. Responsive overrides
"md:p-6 lg:flex-row"
)}
常用工具类模式
// Centering
"flex items-center justify-center"
"grid place-items-center"
// Card pattern
"rounded-lg border bg-card p-6 shadow-sm"
// Interactive element
"cursor-pointer transition-colors hover:bg-accent"
// Focus ring (accessibility)
"focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
// Truncation
"truncate" // Single line
"line-clamp-2" // Multi-line (2 lines)
// Aspect ratios
"aspect-video" // 16:9
"aspect-square" // 1:1
// Backdrop blur (modals, overlays)
"bg-background/80 backdrop-blur-sm"
// Dividers
"divide-y divide-border"
// Screen reader only
"sr-only"
响应式设计模式
// Stack to row
<div className="flex flex-col gap-4 md:flex-row">
// Grid columns
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
// Hide/show
<div className="hidden md:block"> // Show on md+
<div className="md:hidden"> // Hide on md+
// Responsive text
<h1 className="text-3xl md:text-4xl lg:text-5xl">
// Responsive spacing
<section className="py-12 md:py-16 lg:py-24">
动画模式
// Subtle hover lift
"transition-transform hover:-translate-y-1"
// Fade in on hover
"opacity-0 group-hover:opacity-100 transition-opacity"
// Scale on hover
"transition-transform hover:scale-105"
// Color transition
"transition-colors hover:bg-accent"
// Combined
"transition-all duration-200 hover:shadow-lg hover:-translate-y-0.5"
无障碍访问
必需实践
语义化 HTML
// ✅ Correct
<main>
<header>
<nav aria-label="Main navigation">
</header>
<article>
<h1>Page Title</h1>
<section aria-labelledby="section-heading">
<h2 id="section-heading">Section</h2>
</section>
</article>
<footer>
</main>
// ❌ Avoid
<div className="header">
<div className="nav">
<div className="main">
焦点管理
// Visible focus states
"focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
// Focus within (for form groups)
"focus-within:ring-2 focus-within:ring-ring"
// Skip link
<a
href="#main-content"
className="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4"
>
Skip to content
</a>
屏幕阅读器支持
// Hidden but accessible text
<span className="sr-only">Open menu</span>
// Aria labels
<button aria-label="Close dialog">
<XIcon className="h-4 w-4" />
</button>
// Live regions for dynamic content
<div aria-live="polite" aria-atomic="true">
{statusMessage}
</div>
图像无障碍访问
// Informative images
<img src="/chart.png" alt="Sales increased 25% in Q4 2024" />
// Decorative images
<img src="/decoration.png" alt="" role="presentation" />
// Complex images
<figure>
<img src="/diagram.png" alt="System architecture diagram" />
<figcaption>
Detailed description of the architecture...
</figcaption>
</figure>
颜色对比度
- 文本: 对比度至少为 4.5:1(WCAG AA)
- 大号文本: 对比度至少为 3:1
- 交互元素: 具有清晰的视觉区分
- 切勿仅依赖颜色来传达信息
键盘导航
// Interactive elements must be keyboard accessible
<button>Clickable</button> // ✅ Naturally focusable
<div onClick={...}>Clickable</div> // ❌ Not keyboard accessible
// If you must use a div:
<div
role="button"
tabIndex={0}
onClick={handleClick}
onKeyDown={(e) => e.key === 'Enter' && handleClick()}
>
Clickable
</div>
性能
图像优化
import Image from 'next/image'
// Always use Next.js Image component
<Image
src="/hero.jpg"
alt="Hero image description"
width={1200}
height={600}
priority // Above-the-fold images
className="object-cover"
/>
// Responsive images
<Image
src="/photo.jpg"
alt="Description"
fill
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
className="object-cover"
/>
代码拆分
// Dynamic imports for heavy components
import dynamic from 'next/dynamic'
const HeavyChart = dynamic(() => import('@/components/heavy-chart'), {
loading: () => <ChartSkeleton />,
ssr: false // If client-only
})
加载状态
// Skeleton loading (preferred)
<div className="animate-pulse">
<div className="h-4 w-3/4 rounded bg-muted" />
<div className="mt-2 h-4 w-1/2 rounded bg-muted" />
</div>
// Spinner for actions
<Button disabled>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Loading...
</Button>
数据获取
// ✅ Server Components for static data
async function ProductList() {
const products = await getProducts()
return <ProductGrid products={products} />
}
// ✅ SWR for client-side data
import useSWR from 'swr'
function UserProfile() {
const { data, error, isLoading } = useSWR('/api/user', fetcher)
if (isLoading) return <ProfileSkeleton />
if (error) return <ErrorState />
return <Profile user={data} />
}
// ❌ Never fetch in useEffect
useEffect(() => {
fetch('/api/data').then(...) // Anti-pattern
}, [])
代码组织
项目结构
app/
├── (marketing)/ # Route groups for layouts
│ ├── page.tsx
│ ├── about/
│ └── pricing/
├── (dashboard)/
│ ├── layout.tsx
│ └── dashboard/
├── api/
│ └── [feature]/
│ └── route.ts
├── layout.tsx
└── globals.css
components/
├── ui/ # shadcn components
├── [feature]/ # Feature components
├── layout/ # Layout components
└── shared/ # Shared components
lib/
├── utils.ts # Utility functions
├── validations.ts # Zod schemas
└── constants.ts # App constants
hooks/
├── use-[feature].ts
└── use-media-query.ts
types/
└── index.ts
命名约定
| 类型 | 约定 | 示例 |
|---|---|---|
| 组件 | PascalCase | FeatureCard.tsx |
| 文件 | kebab-case | feature-card.tsx |
| Hooks | camelCase,使用 use 前缀 | useFeature.ts |
| 工具函数 | camelCase | formatDate.ts |
| 类型 | PascalCase | FeatureProps |
| 常量 | SCREAMING_SNAKE_CASE | MAX_FILE_SIZE |
| CSS 变量 | kebab-case | --primary-color |
导入组织
// 1. React/Next.js
import { useState, useEffect } from 'react'
import Image from 'next/image'
import Link from 'next/link'
// 2. Third-party libraries
import { motion } from 'framer-motion'
import { z } from 'zod'
// 3. Internal components
import { Button } from '@/components/ui/button'
import { FeatureCard } from '@/components/feature/feature-card'
// 4. Internal utilities/hooks
import { cn } from '@/lib/utils'
import { useFeature } from '@/hooks/use-feature'
// 5. Types
import type { Feature } from '@/types'
UI/UX 原则
视觉层次
- 大小 — 较大的元素会优先吸引注意力
- 颜色 — 高饱和度颜色在中性色背景下更醒目
- 对比度 — 高对比度可形成视觉焦点
- 间距 — 留白可突出重要元素
- 位置 — 按从左上到右下的顺序阅读
交互状态
每个交互元素都需要具备以下状态:
// Button example
<button className={cn(
// Default
"bg-primary text-primary-foreground",
// Hover
"hover:bg-primary/90",
// Focus
"focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
// Active/Pressed
"active:scale-[0.98]",
// Disabled
"disabled:pointer-events-none disabled:opacity-50"
)}>
反馈模式
// Loading feedback
<Button disabled={isLoading}>
{isLoading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Saving...
</>
) : (
'Save Changes'
)}
</Button>
// Success feedback
<div className="flex items-center gap-2 text-green-600">
<CheckCircle className="h-4 w-4" />
<span>Changes saved successfully</span>
</div>
// Error feedback
<div className="rounded-md bg-destructive/10 p-4 text-destructive">
<p className="text-sm font-medium">Error occurred</p>
<p className="mt-1 text-sm opacity-90">{error.message}</p>
</div>
空状态
切勿显示空白屏幕。始终提供有帮助的空状态:
<div className="flex flex-col items-center justify-center py-12 text-center">
<InboxIcon className="h-12 w-12 text-muted-foreground/50" />
<h3 className="mt-4 text-lg font-semibold">No messages yet</h3>
<p className="mt-2 text-sm text-muted-foreground">
When you receive messages, they'll appear here.
</p>
<Button className="mt-4">
Send your first message
</Button>
</div>
微交互
增强 UX 的细微动画:
// Hover lift effect
"transition-transform duration-200 hover:-translate-y-1 hover:shadow-lg"
// Button press effect
"active:scale-[0.98] transition-transform"
// Smooth reveals
"animate-in fade-in slide-in-from-bottom-4 duration-300"
// Skeleton pulse
"animate-pulse"
常见模式
主视觉区域
<section className="relative overflow-hidden py-24 md:py-32 lg:py-40">
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div className="mx-auto max-w-3xl text-center">
<h1 className="text-balance text-4xl font-bold tracking-tight md:text-5xl lg:text-6xl">
Your compelling headline here
</h1>
<p className="mt-6 text-pretty text-lg text-muted-foreground md:text-xl">
Supporting text that elaborates on the headline and provides context.
</p>
<div className="mt-8 flex flex-col gap-4 sm:flex-row sm:justify-center">
<Button size="lg">Primary Action</Button>
<Button size="lg" variant="outline">Secondary Action</Button>
</div>
</div>
</div>
</section>
功能网格
<section className="py-16 md:py-24">
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div className="mx-auto max-w-2xl text-center">
<h2 className="text-3xl font-bold md:text-4xl">Features</h2>
<p className="mt-4 text-muted-foreground">
Everything you need to succeed.
</p>
</div>
<div className="mt-12 grid gap-8 sm:grid-cols-2 lg:grid-cols-3">
{features.map((feature) => (
<FeatureCard key={feature.id} {...feature} />
))}
</div>
</div>
</section>
卡片网格
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
{items.map((item) => (
<Card key={item.id} className="group overflow-hidden">
<div className="aspect-video overflow-hidden">
<Image
src={item.image}
alt={item.title}
fill
className="object-cover transition-transform group-hover:scale-105"
/>
</div>
<CardHeader>
<CardTitle>{item.title}</CardTitle>
<CardDescription>{item.description}</CardDescription>
</CardHeader>
<CardFooter>
<Button variant="ghost" className="ml-auto">
Learn more <ArrowRight className="ml-2 h-4 w-4" />
</Button>
</CardFooter>
</Card>
))}
</div>
便当网格
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{/* Large feature - spans 2 columns */}
<div className="md:col-span-2 lg:row-span-2 rounded-xl border bg-card p-6">
<h3 className="text-2xl font-bold">Main Feature</h3>
</div>
{/* Regular items */}
<div className="rounded-xl border bg-card p-6">
<h3 className="font-semibold">Feature 2</h3>
</div>
<div className="rounded-xl border bg-card p-6">
<h3 className="font-semibold">Feature 3</h3>
</div>
{/* Wide item - spans 2 columns */}
<div className="md:col-span-2 rounded-xl border bg-card p-6">
<h3 className="font-semibold">Wide Feature</h3>
</div>
</div>
表单布局
<form className="space-y-6">
<div className="grid gap-4 sm:grid-cols-2">
<div className="space-y-2">
<Label htmlFor="firstName">First name</Label>
<Input id="firstName" placeholder="John" />
</div>
<div className="space-y-2">
<Label htmlFor="lastName">Last name</Label>
<Input id="lastName" placeholder="Doe" />
</div>
</div>
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input id="email" type="email" placeholder="[email protected]" />
<p className="text-sm text-muted-foreground">
We'll never share your email.
</p>
</div>
<Button type="submit" className="w-full sm:w-auto">
Submit
</Button>
</form>
导航
<header className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<div className="mx-auto flex h-16 max-w-7xl items-center justify-between px-4 sm:px-6 lg:px-8">
<Link href="/" className="flex items-center gap-2">
<Logo className="h-8 w-8" />
<span className="font-bold">Brand</span>
</Link>
<nav className="hidden items-center gap-6 md:flex">
<Link href="/features" className="text-sm font-medium text-muted-foreground transition-colors hover:text-foreground">
Features
</Link>
<Link href="/pricing" className="text-sm font-medium text-muted-foreground transition-colors hover:text-foreground">
Pricing
</Link>
</nav>
<div className="flex items-center gap-4">
<Button variant="ghost" size="sm" className="hidden sm:flex">
Sign in
</Button>
<Button size="sm">Get Started</Button>
</div>
</div>
</header>
应避免的反模式
颜色误用
// ❌ Too many colors
className="bg-purple-500 text-pink-400 border-blue-300 shadow-green-200"
// ❌ Direct colors instead of tokens
className="bg-white text-black"
// ❌ Purple/violet as primary (unless explicitly requested)
className="bg-violet-600"
// ❌ Clashing temperature gradients
className="bg-gradient-to-r from-pink-500 to-green-500"
// ✅ Semantic tokens
className="bg-background text-foreground"
排版误用
// ❌ Too many fonts
<h1 className="font-display">
<p className="font-body">
<span className="font-accent">
<code className="font-mono"> // 4 fonts!
// ❌ Tiny text
className="text-xs" // Avoid for body text
// ❌ No line-height consideration
className="text-base" // Missing leading-*
// ✅ Proper typography
className="text-base leading-relaxed"
布局误用
// ❌ Desktop-first responsive
className="w-1/3 sm:w-1/2 xs:w-full"
// ❌ Using space-* utilities
className="space-y-4"
// ❌ Floats
className="float-left"
// ❌ Mixing gap and margin
className="flex gap-4 mb-4"
// ✅ Mobile-first with gap
className="flex flex-col gap-4 md:flex-row"
组件误用
// ❌ Monolithic page files (500+ lines)
// ❌ Hardcoded values instead of props
// ❌ Inline styles
// ❌ Non-semantic HTML (div for everything)
// ❌ Missing key props in lists
// ❌ Fetching in useEffect
// ✅ Split into components
// ✅ Use props for customization
// ✅ Tailwind classes
// ✅ Semantic HTML
// ✅ Proper key props
// ✅ Server Components or SWR
无障碍访问问题
// ❌ Click handler on div
<div onClick={handleClick}>Click me</div>
// ❌ Missing alt text
<img src="/photo.jpg" />
// ❌ Color-only indication
<span className="text-red-500">Error</span>
// ❌ Missing focus states
<button className="hover:bg-accent">
// ✅ Use button element
<button onClick={handleClick}>Click me</button>
// ✅ Descriptive alt text
<img src="/photo.jpg" alt="Team meeting in conference room" />
// ✅ Icon + color for errors
<span className="flex items-center gap-2 text-destructive">
<AlertCircle className="h-4 w-4" />
Error message
</span>
// ✅ Focus states
<button className="hover:bg-accent focus:ring-2 focus:ring-ring">
视觉问题
// ❌ Abstract decorative shapes
<div className="absolute -top-20 -right-20 h-40 w-40 rounded-full bg-gradient-to-r from-purple-400 to-pink-400 blur-3xl" />
// ❌ Placeholder images left in production
<img src="/placeholder.jpg" />
// ❌ Emojis as icons
<span>📧 Email</span>
// ❌ Hand-drawn SVG maps
<svg><path d="M100,200 L300,400..." /></svg>
// ✅ Real images or GenerateImage tool
// ✅ Proper icon libraries (Lucide, etc.)
// ✅ Mapping libraries for geographic data
快速参考清单
发布前,请确认:
- 颜色: 最多 3-5 种,使用语义化令牌
- 排版: 最多 2 种字体,层次清晰
- 间距: 保持一致,使用 Tailwind 比例
- 移动端: 在 375px 宽度下显示良好
- 无障碍访问: 键盘导航、焦点状态、替代文本
- 性能: 图像已优化,代码已拆分
- 组件: 按逻辑拆分,避免臃肿
- 加载: 为异步内容提供骨架屏状态
- 空状态: 无数据时显示有帮助的提示
- 错误: 提供清晰的错误提示和恢复方式
- 交互: 定义悬停、焦点、激活状态
总结
v0 方案可以概括为:
克制而优雅,交互有的放矢。
每项设计决策都应通过以下检验:
- 是否提升了清晰度?
- 是否保持了一致性?
- 是否有助于实现用户目标?
- 如果删掉它,设计是否会变差?
如果无法对这四项都回答“是”,请重新考虑这一选择。
评论
支持 Markdown