软件工程师设计原则
面向软件工程师的设计基础:涵盖排版、色彩、间距、动画、AI界面模式、设计令牌,以及当今48个产品案例研究。
更新于2026年8月18日
2026年5月18日更新:更新了设计研究索引,使其与当前包含48项研究的资料库保持一致;同时扩展了AI界面模式,加入智能体工作流的实践依据:检查点、审批状态、来源可信度和可见的验证过程。
2026年5月更新:新增关于WCAG 3.0于2026年3月发布的工作草案,以及W3C认为WCAG 2.2与3.0将并行存在的说明。对于当前的无障碍工作,WCAG 2.2仍是应遵循的标准。
2026年2月更新:新增两个章节——交互模式(通过研究Framer、Flighty、Halide、Warp、Bear、Craft和Superhuman总结出的8种范式)和AI界面模式(借鉴Perplexity的引用优先设计、流式阶段和错误透明机制)。将Web模式更新至2026年,涵盖锚点定位、滚动驱动动画和@starting-style。更新无障碍部分,以反映WCAG 2.2已成为ISO标准。有关48款杰出产品的深入剖析,请参阅设计研究。
多年来,我一边构建软件,一边钻研设计。我汲取了Dieter Rams等设计大师的理念,也深入剖析了Linear、Stripe和Raycast等产品的界面。本指南将这些理解提炼成一份全面的参考资料——这正是我刚开始重视软件外观与体验时,希望能够读到的指南。
设计不是装饰,而是沟通。每一个像素都在传达功能、层级与含义。业余软件与专业软件之间的差别,在于是否理解这些原则,并始终如一地加以运用。
本指南假定您已经能够编写代码。它将教会您如何观察——理解为何有些界面用起来毫不费力,而另一些却杂乱无章;更重要的是,掌握如何构建前者。
目录
第一部分:基础理论
第二部分:交互与 AI
第三部分:设计哲学
第四部分:实现
第五部分:参考
Gestalt 心理学
“整体并非部分之和,而是另一回事。” — Kurt Koffka
Gestalt 心理学诞生于 1920 年代的德国,研究人类如何感知视觉信息。大脑并不逐个像素地处理画面,而是将元素组织为有意义的模式。掌握这些原则,就能主动引导用户对界面的感知。
邻近性
相互靠近的元素会被视为一组。
这是 UI 设计中最强大的 Gestalt 原则。空间比任何其他视觉属性都更能传达元素间的关系。
WRONG (equal spacing = no grouping):
┌─────────────────┐
│ Label │
│ │
│ Input Field │
│ │
│ Label │
│ │
│ Input Field │
└─────────────────┘
RIGHT (unequal spacing = clear groups):
┌─────────────────┐
│ Label │
│ Input Field │ ← Tight (4px) - related
│ │
│ │ ← Wide (24px) - separating groups
│ Label │
│ Input Field │ ← Tight (4px) - related
└─────────────────┘
CSS 实现:
.form-group {
margin-bottom: 24px; /* Between groups: wide */
}
.form-group label {
margin-bottom: 4px; /* Label to input: tight */
display: block;
}
SwiftUI 实现:
VStack(alignment: .leading, spacing: 4) { // Tight within group
Text("Email")
.font(.caption)
.foregroundStyle(.secondary)
TextField("you@example.com", text: $email)
.textFieldStyle(.roundedBorder)
}
.padding(.bottom, 24) // Wide between groups
相似性
具有相同视觉特征的元素会被视为相关联。
当元素外观一致时,用户会认为它们功能一致。这正是设计系统要求按钮样式、卡片样式和字体排印保持统一的原因。
Example Navigation:
┌───────────────────────────────────┐
│ [Dashboard] [Projects] [Settings] │ ← Same style = same function
│ │
│ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │Card │ │Card │ │Card │ │ ← Same style = same content type
│ └─────┘ └─────┘ └─────┘ │
│ │
│ [+ New Project] │ ← Different style = different function
└───────────────────────────────────┘
图形-背景关系
内容应清晰地从背景中区分出来。
大脑需要区分”图形”(关注的焦点)和”背景”(衬托的底层)。图形-背景关系处理不当会造成视觉混乱。
常用技巧: - 对比度(亮色图形搭配暗色背景,或反之) - 阴影(将图形从背景中”抬起”) - 边框(勾勒图形轮廓) - 模糊(虚化背景,锐化前景)
/* Strong figure-ground relationship */
.card {
background: var(--color-surface); /* Figure */
border-radius: 12px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1); /* Elevation */
}
.modal-overlay {
background: rgba(0, 0, 0, 0.5); /* Dim ground */
backdrop-filter: blur(4px); /* Blur ground */
}
公共区域
位于同一边界内的元素会被视为一组。
将元素放入可视容器(卡片、方框、带边框的区域)中,即传达了”它们属于一体”的信号。
连续性
视线会沿着路径、线条和曲线自然延伸。
利用对齐与视觉流引导用户的注意力贯穿整个界面。
CONTINUITY IN ALIGNMENT:
┌────────────────────────────────┐
│ Logo [Nav] [Nav] [Nav] │ ← Aligned on horizontal axis
├────────────────────────────────┤
│ │
│ Headline │
│ ───────────────────────────── │ ← Eye follows left edge
│ Paragraph text continues │
│ along the same left edge │
│ │
│ [Primary Action] │ ← Still on the left edge
└────────────────────────────────┘
闭合性
大脑会自动补全不完整的形状。
用户不需要看到每一个像素——他们会在心中补全熟悉的形状。这使得更简洁、更精致的设计成为可能。
/* Horizontal scroll with partial card (closure) */
.card-carousel {
display: flex;
gap: 16px;
overflow-x: auto;
padding-right: 48px; /* Show partial card = scroll hint */
}
.card-carousel .card {
flex: 0 0 280px; /* Fixed width, partial visible */
}
Gestalt 速查表
| 原则 | 规则 | 主要用途 |
|---|---|---|
| 邻近性 | 相关的靠近,无关的远离 | 表单字段、内容分区 |
| 相似性 | 外观一致 = 功能一致 | 按钮、卡片、导航 |
| 图形-背景 | 层次分离要清晰 | 卡片、弹窗、覆盖层 |
| 公共区域 | 边界将内容归组 | 设置分区、用户卡片 |
| 连续性 | 沿线条和对齐方向引导视线 | 时间线、阅读流 |
| 闭合性 | 大脑会补全形状 | 图标、滚动提示、骨架屏 |
字体排印
“字体排印是赋予人类语言以持久视觉形态的工艺。” — Robert Bringhurst
字体排印是界面设计的基石。文字承载着功能、层级与品牌。糟糕的排印让界面更难用;出色的排印则浑然天成——用户甚至察觉不到它的存在。
字号比例
一致的比例尺创造视觉和谐。建议采用数学比率。
1.25 比例(推荐用于 UI):
:root {
/* Base: 16px (1rem) */
--text-xs: 0.64rem; /* 10.24px - use sparingly */
--text-sm: 0.8rem; /* 12.8px - captions, labels */
--text-base: 1rem; /* 16px - body text */
--text-lg: 1.25rem; /* 20px - lead text */
--text-xl: 1.563rem; /* 25px - h4 */
--text-2xl: 1.953rem; /* 31.25px - h3 */
--text-3xl: 2.441rem; /* 39px - h2 */
--text-4xl: 3.052rem; /* 48.8px - h1 */
}
行高(行距)
行高对可读性有极大影响。不同内容需要不同的行距设置。
| 内容类型 | 行高 | 原因 |
|---|---|---|
| 标题 | 1.1 - 1.2 | 紧凑、醒目、篇幅短 |
| UI 文字 | 1.3 - 1.4 | 标签、按钮 |
| 正文 | 1.5 - 1.7 | 提升段落可读性 |
| 长文 | 1.7 - 2.0 | 文章、技术文档 |
行宽(版面宽度)
合适的行宽可以减轻视觉疲劳,提升阅读理解力。
- 最佳范围: 每行 45-75 个字符
- 目标值: 50-65 个字符
- 绝对上限: 85 个字符
p {
max-width: 65ch; /* ch unit = width of '0' character */
}
.article-body {
max-width: 70ch;
margin: 0 auto;
}
字体选择
优先使用系统字体。 加载零延迟,与平台风格一致,且针对屏幕显示做过优化。
:root {
--font-sans: system-ui, -apple-system, BlinkMacSystemFont,
'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
--font-mono: ui-monospace, 'SF Mono', 'Cascadia Code',
'JetBrains Mono', Consolas, monospace;
}
适合使用自定义字体的场景: - 品牌差异化(营销类网站) - 追求编辑出版质感 - 系统字体无法实现的特定设计意图
用字重建立层级
通过字重而非仅靠字号来构建视觉层级。
h1 { font-weight: 700; } /* Bold */
h2 { font-weight: 600; } /* Semibold */
h3 { font-weight: 600; } /* Semibold */
.lead { font-weight: 500; } /* Medium */
p { font-weight: 400; } /* Regular */
.meta { font-weight: 400; color: var(--text-muted); }
字体排印速查表
| 属性 | 正文 | 标题 | UI 标签 |
|---|---|---|---|
| 字号 | 16-18px | 24-48px | 12-14px |
| 字重 | 400 | 600-700 | 500 |
| 行高 | 1.5-1.7 | 1.1-1.2 | 1.3-1.4 |
| 行宽 | 45-75ch | 不适用 | 不适用 |
| 对齐 | 左对齐 | 居中亦可 | 左对齐 |
色彩理论
“色彩是一种直接影响灵魂的力量。”——Wassily Kandinsky
色彩传达信息的速度快于文字。它营造情绪、引导注意力、传递意义,并建立品牌识别度。
60-30-10规则
用于构建均衡界面最可靠的色彩分配方式。
┌──────────────────────────────────────────┐
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ 60% - Dominant (Background)
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
│░░░░░▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░│ 30% - Secondary (Cards, sections)
│░░░░░▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░│
│░░░░░▓▓▓▓▓▓▓▓▓▓▓▓██████▓▓▓▓▓▓▓▓▓▓░░░░░░░░│ 10% - Accent (Buttons, links)
└──────────────────────────────────────────┘
构建配色方案
每个界面都需要这些语义色彩:
:root {
/* Brand */
--color-primary: hsl(220, 80%, 50%);
--color-primary-hover: hsl(220, 80%, 45%);
/* Semantic */
--color-success: hsl(142, 76%, 36%); /* Green - positive */
--color-warning: hsl(38, 92%, 50%); /* Amber - caution */
--color-error: hsl(0, 84%, 60%); /* Red - danger */
/* Neutrals */
--color-background: hsl(0, 0%, 100%);
--color-surface: hsl(220, 14%, 96%);
--color-border: hsl(220, 13%, 91%);
/* Text */
--color-text: hsl(220, 13%, 13%);
--color-text-secondary: hsl(220, 9%, 46%);
--color-text-muted: hsl(220, 9%, 64%);
}
色彩心理学
| 颜色 | 心理联想 | UI用途 |
|---|---|---|
| 蓝色 | 信任、稳定、平静 | 金融、科技、企业 |
| 绿色 | 成长、自然、成功 | 健康、环保、正向状态 |
| 红色 | 能量、紧迫、危险 | 警报、销售、错误 |
| 橙色 | 温暖、热情 | CTAs、活泼品牌 |
| 黄色 | 乐观、警示 | 警告、重点突出 |
| 紫色 | 奢华、创造力 | 高端产品 |
| ### 暗色模式优先设计(Vercel) | ||
| Vercel先以深色模式为设计基础,再推导出浅色模式。这样能打造更出色的深色界面,因为深色模式成为首要考量,而非事后补充。 |
/* Design dark first, derive light */
:root {
/* Dark mode defaults */
--color-background: hsl(0, 0%, 0%);
--color-surface: hsl(0, 0%, 7%);
--color-border: hsl(0, 0%, 15%);
--color-text: hsl(0, 0%, 93%);
--color-text-secondary: hsl(0, 0%, 63%);
}
@media (prefers-color-scheme: light) {
:root {
--color-background: hsl(0, 0%, 100%);
--color-surface: hsl(0, 0%, 97%);
--color-border: hsl(0, 0%, 89%);
--color-text: hsl(0, 0%, 9%);
--color-text-secondary: hsl(0, 0%, 40%);
}
}
适用场景:开发者工具、媒体应用、仪表盘——用户长时间使用的场景,深色模式有助于减轻眼睛疲劳。
无障碍对比度
| 级别 | 常规文本 | 大号文本 | UI组件 |
|---|---|---|---|
| AA | 4.5:1 | 3:1 | 3:1 |
| AAA | 7:1 | 4.5:1 | N/A |
| WCAG 2.2于2025年10月成为ISO标准(ISO/IEC 40500:2025),新增了焦点可见性、冗余输入和可访问身份验证方面的准则。关键新增内容包括:焦点指示器不得被其他内容完全遮挡(2.4.11),身份验证不得仅依赖认知功能测试(3.3.8)。W3C于2024年12月发布了更新版WCAG 2.2,预计将在2026年末前作为ISO/IEC 40500:2026发布。 |
WCAG 3.0仍处于工作草案阶段。最新修订版已于2026年3月发布,但它并不是WCAG 2.2的替代标准;W3C表示这两项标准将并存。Accessibility Guidelines Working Group计划在2026年发布预计的WCAG 3时间线,但对于当前工作,WCAG 2.2仍是应遵循的标准。
工具:WebAIM Contrast Checker、Chrome DevTools取色器
视觉层级
“设计是品牌的无声大使。”——Paul Rand
视觉层级决定用户首先、其次和再次看到什么。没有清晰的层级,用户就必须费力查找信息。有了它,界面才会显得轻松自然。
层级的六种工具
1. 大小——较大的元素会率先吸引注意力
.hero-title { font-size: 3rem; } /* Dominant */
.section-title { font-size: 1.5rem; } /* Secondary */
.body-text { font-size: 1rem; } /* Baseline */
2. 字重——粗体更加突出,细体则退居次要位置
h1 { font-weight: 700; }
.lead { font-weight: 500; }
p { font-weight: 400; }
3. 颜色与对比度——高对比度=吸引注意力
.title { color: var(--color-text); } /* Near black */
.meta { color: var(--color-text-muted); } /* Gray */
4. 位置——关键位置至关重要
F-PATTERN (content pages): Z-PATTERN (landing pages):
████████████████████████ 1 ──────────────────► 2
████████ ↘
████ ↘
██ ↘
3 ──────────────────► 4
5. 留白——孤立呈现会凸显重要性
.hero { padding: 120px 48px; } /* Generous space */
.data-table { padding: 12px; } /* Dense content */
6. 深度与抬升——向前凸显的元素会吸引注意力
:root {
--shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
--shadow-md: 0 4px 6px rgba(0,0,0,0.1);
--shadow-lg: 0 10px 15px rgba(0,0,0,0.1);
}
.card { box-shadow: var(--shadow-sm); }
.card:hover { box-shadow: var(--shadow-md); }
.modal { box-shadow: var(--shadow-lg); }
应用模式
协作临场感(Figma):多个用户光标配合姓名标签、选区高亮和组件轮廓,让文档呈现实时协作的生命力。每位协作者的颜色都清晰可辨,但权重相同——没有哪个光标比另一个更“显眼”。
环境式状态指示器(Vercel):部署状态使用细微、持续存在的指示器,而不是打断流程的警报。顶部一条细窄的色条即可传达状态(构建中、已部署、失败),同时不干扰工作流。
现实世界设计类比(Flighty):航班进度可视化借鉴真实航空仪表——高度曲线、速度指示器和登机口地图都使用熟悉的视觉隐喻,而不是抽象的进度条。
眯眼测试
眯起眼看您的设计。还能看出层级吗?如果可以,说明层级足够清晰。
间距与节奏
“空白就像空气:设计需要它来呼吸。”——Wojciech Zieliński
间距是设计中看不见的结构。一致的间距会形成视觉节奏——让元素在一个连贯的系统中显得彼此归属。
8px网格
8px网格是行业标准,原因如下: - 可等距递增(8、16、24、32、40、48……) - 适用于常见屏幕密度(1x、1.5x、2x、3x) - 无需计算即可形成一致的节奏
:root {
--space-1: 4px; /* Tight: icon gaps */
--space-2: 8px; /* Compact: inline elements */
--space-3: 12px; /* Snug: form fields */
--space-4: 16px; /* Default: most gaps */
--space-6: 24px; /* Spacious: card padding */
--space-8: 32px; /* Section gaps */
--space-12: 48px; /* Major sections */
--space-16: 64px; /* Page sections */
--space-20: 80px; /* Hero spacing */
}
内部间距与外部间距
内部间距(padding): 元素内部的空间 外部间距(margin): 元素之间的空间
规则: 在相关分组内,内部间距通常应大于外部间距。
.card {
padding: 24px; /* Internal: spacious */
margin-bottom: 16px; /* External: less than padding */
}
组件间距模式
卡片:
.card { padding: 24px; border-radius: 12px; }
.card-header { margin-bottom: 16px; }
.card-title { margin-bottom: 4px; } /* Tight to subtitle */
按钮:
.btn { padding: 12px 24px; border-radius: 8px; }
.btn--sm { padding: 8px 16px; }
.btn--lg { padding: 16px 32px; }
.btn-group { display: flex; gap: 12px; }
表单:
.form-row { margin-bottom: 24px; }
.form-label { margin-bottom: 4px; }
.form-help { margin-top: 4px; }
.form-actions { margin-top: 32px; display: flex; gap: 12px; }
间距快速参考
| 上下文 | 推荐间距 |
|---|---|
| 图标与文本之间 | 4-8px |
| 标签与输入框之间 | 4px |
| 表单组之间 | 24px |
| 卡片内边距 | 20-24px |
| 卡片间距 | 16-24px |
| 区块内边距(移动端) | 48-64px |
| 区块内边距(桌面端) | 80-96px |
| 按钮内边距(水平/垂直) | 24px / 12px |
| — |
动画原则
“动画不是让画动起来的艺术,而是把动态画出来的艺术。” — Norman McLaren
动画赋予界面生命力。运用得当,它能引导注意力、传达状态、建立情感连接;运用失当,则令人烦躁、分散注意。
核心原则
动画应浑然天成,而非装饰点缀。
好的动画: 1. 传达静态设计无法表达的信息 2. 通过展示关系来降低认知负荷 3. 自然流畅,符合预期 4. 融入体验,不被有意识地察觉
差的动画: 1. 存在的理由仅仅是”看起来酷” 2. 拖慢用户操作节奏 3. 刻意吸引注意力 4. 制造焦虑或不耐烦
UI 动画关键原则
1. 预备动作(Anticipation) — 为即将发生的变化做铺垫。
.button {
transition: transform 0.1s ease-out;
}
.button:active {
transform: scale(0.97); /* Slight press before action */
}
2. 惯性跟随(Follow-Through) — 让运动以弹簧般的回弹自然收尾。
.panel {
transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
withAnimation(.spring(response: 0.4, dampingFraction: 0.7)) {
isOpen = true
}
3. 缓入缓出(Ease-In, Ease-Out) — 自然界中没有匀速运动。
| 曲线 | 适用场景 | 特征 |
|---|---|---|
ease-out |
元素进入 | 快速启动,平缓停止 |
ease-in |
元素退出 | 平缓启动,快速消失 |
ease-in-out |
状态切换 | 全程流畅 |
linear |
加载指示器 | 持续、机械 |
4. 聚焦编排(Staging) — 将注意力引导到关键内容上。除非作为整体编排,否则同一时刻只应有一个元素在运动。
5. 错落入场(Staggering) — 元素应依次出现,而非同时涌入。
.list-item {
animation: fadeSlideIn 0.3s ease-out both;
}
.list-item:nth-child(1) { animation-delay: 0ms; }
.list-item:nth-child(2) { animation-delay: 50ms; }
.list-item:nth-child(3) { animation-delay: 100ms; }
.list-item:nth-child(4) { animation-delay: 150ms; }
@keyframes fadeSlideIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
时长指南
| 时长 | 适用场景 | 感受 |
|---|---|---|
| 50-100ms | 微交互(悬停、按压) | 即时反馈 |
| 150-200ms | 简单状态变化(开关、选中) | 干脆利落 |
| 250-350ms | 中等过渡(面板滑入、卡片翻转) | 流畅自然 |
| 400-500ms | 大幅运动(页面过渡、模态框) | 沉稳从容 |
性能:黄金法则
只对 transform 和 opacity 做动画 — 它们经过GPU加速,不会触发布局重排。
/* BAD: Animating layout */
.panel { transition: left 0.3s, width 0.3s; }
/* GOOD: Using transform */
.panel { transition: transform 0.3s; }
何时不该使用动画
-
用户启用了
prefers-reduced-motioncss @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } } -
动画不传达任何信息 — 多余的旋转、弹跳元素
- 用户赶时间 — 错误状态、表单验证、搜索结果
- 动画会拖慢重复操作 — 键盘快捷键应跳过动画
- 数据已加载完毕 — Bear 通过预加载内容实现零等待状态,让应用体验如丝般顺滑。如果能预加载,就直接跳过骨架屏和加载动画。
// Bear's approach: preload so no loading state is needed
struct NoteListView: View {
@Query var notes: [Note] // SwiftData loads from disk instantly
// No loading state, no skeleton, no spinner — data is always there
var body: some View {
List(notes) { note in
NoteRow(note: note)
}
}
}
动画速查表
:root {
/* Durations */
--duration-instant: 0.1s;
--duration-fast: 0.15s;
--duration-normal: 0.25s;
--duration-slow: 0.4s;
/* Easings */
--ease-out: cubic-bezier(0.0, 0.0, 0.58, 1.0);
--ease-in: cubic-bezier(0.42, 0.0, 1.0, 1.0);
--ease-in-out: cubic-bezier(0.42, 0.0, 0.58, 1.0);
--ease-out-back: cubic-bezier(0.34, 1.56, 0.64, 1);
}
交互模式
“最好的界面就是没有界面。” — Golden Krishna
交互模式定义了用户如何操控、导航和理解产品。以下模式提炼自对那些交互体验卓越的产品的深入研究。
直接操控(Framer)
让抽象概念变得可触可感。Framer 将CSS断点——原本抽象的数值——转化为可拖拽的控制手柄,用户能实时看到布局的响应变化。
/* Breakpoint handle styling */
.breakpoint-handle {
position: absolute;
top: 0;
bottom: 0;
width: 4px;
background: var(--accent);
cursor: col-resize;
opacity: 0.6;
transition: opacity 0.15s ease;
}
.breakpoint-handle:hover,
.breakpoint-handle:active {
opacity: 1;
width: 6px;
}
适用场景: 任何结果可视化的设置——拖拽调整大小、颜色选择器、时间轴拖拽。
上下文感知界面(Flighty、Figma)
只展示当前时刻相关的信息。Flighty 使用 15 种不同状态来追踪航班。Figma 的属性面板会根据选中对象完全变换。
| 阶段(Flighty) | 用户看到的内容 |
|---|---|
| 起飞前 24 小时 | 确认码、航站楼信息 |
| 到达机场 | 登机口、登机时间 |
| 飞行中 | 剩余时间、进度、预计到达时间 |
| 着陆后 | 中转登机口、步行路线 |
enum ContextState: CaseIterable {
case farOut, dayBefore, headToAirport, atAirport
case atGate, boarding, inFlight, landed, connection
static func current(for flight: Flight, context: UserContext) -> ContextState {
// Factor in: time, location, flight status
// Return the single most relevant state
}
}
反模式: 显示所有控件,将不相关的灰度处理。这会制造视觉噪音。
智能激活(Halide)
工具应感知上下文并自行激活。Halide 的对焦放大镜在拖动对焦时出现,松手后消失,无需任何切换按钮。
struct IntelligentlyActivated<Content: View>: ViewModifier {
let isInteracting: Bool
@State private var isVisible = false
func body(content: Content) -> some View {
content
.opacity(isVisible ? 1 : 0)
.scaleEffect(isVisible ? 1 : 0.95)
.animation(.easeInOut(duration: 0.2), value: isVisible)
.onChange(of: isInteracting) { _, newValue in
if newValue {
withAnimation { isVisible = true }
} else {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
if !isInteracting { isVisible = false }
}
}
}
}
}
双模式设计(Halide、Warp)
模式切换应彻底变换 UI,而非简单地显隐元素。Halide 的自动模式和手动模式是截然不同的两套界面。Warp 通过四种输入方式(键入、命令面板、AI、鼠标)在CLI和 GUI 之间架起桥梁,而不强迫用户只用一种范式。
结构化内容(Warp、Bear、Craft)
为传统上非结构化的内容赋予结构。Warp 将终端输出转化为可复制、可分享、可重跑的独立块。Bear 支持在写作中通过 #tag/subtag 内联组织笔记。Craft 让任何块都能成为一个页面——结构从使用中自然涌现,而非预设的层级体系。
渐进式训练(Superhuman)
通过反复曝光教会用户高效操作方式。Superhuman 的 Cmd+K 命令面板始终在结果旁显示键盘快捷键,每次使用都是一次微型课程。
/* Always show shortcut alongside command name */
.command-result {
display: flex;
justify-content: space-between;
padding: 8px 12px;
}
.command-shortcut {
font-family: var(--font-mono);
font-size: 12px;
color: var(--text-muted);
background: var(--bg-subtle);
padding: 2px 6px;
border-radius: 4px;
}
反模式: 用教程弹窗解释功能。解释会被遗忘,实践才会被铭记。
AI界面模式
“最佳AI界面能让机器的处理过程清晰可见,并让机器的输出可供验证。”
AI界面面临着独特的挑战:用户无法预测输出结果,无法仅凭查看来验证准确性,而且常常无法判断系统是正在工作还是已经出错。
核心问题
| 传统软件 | AI软件 |
|---|---|
| 输出可预测 | 输出具有不确定性 |
| 错误显而易见 | 错误看似合理 |
| 用户通过测试进行验证 | 用户通过核查来源进行验证 |
| 加载=等待 | 加载=正在工作(应展示过程) |
| 默认信任 | 信任必须逐步赢得 |
引用优先设计(Perplexity)
每项事实性陈述都必须链接至其来源。Perplexity在每项陈述中嵌入行内引用[1],并提供悬停预览和常驻来源面板。
.citation-marker {
position: relative;
color: var(--accent);
cursor: pointer;
font-size: 0.8em;
vertical-align: super;
}
.citation-preview {
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
width: 280px;
padding: 12px;
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
反面模式:AI界面生成的陈述没有可追溯的来源。如果模型无法提供引用,界面应明确标示。
流式阶段指示器(Perplexity)
向用户展示AI正在执行的具体工作,而不只是表明它仍在运行。用阶段指示器取代通用的加载动画:“正在搜索……”→“正在阅读4个来源……”→“正在撰写回答……”
.phase-indicator {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 6px 12px;
background: color-mix(in srgb, var(--phase-color) 10%, transparent);
border-radius: 16px;
font-size: 13px;
color: var(--phase-color);
transition: all 0.3s ease;
}
.loading-dots span {
width: 4px;
height: 4px;
background: currentColor;
border-radius: 50%;
animation: pulse 1.4s ease-in-out infinite;
}
错误透明度
当AI失败或无法确定时,应明确展示情况,而非用貌似自信的文字加以掩饰。
| 情况 | 不良模式 | 良好模式 |
|---|---|---|
| 置信度低 | 以肯定语气陈述 | 使用较弱的视觉样式显示“我无法确定,但……” |
| 未找到来源 | 编造内容 | “我无法为此陈述找到来源” |
| 来源相互矛盾 | 不作说明地选择其一 | 同时展示双方,并突出显示冲突之处 |
| 信息已过时 | 当作当前信息呈现 | 显示“截至[日期]……”,并附上时效性指示器 |
关键洞见:用户会谅解坦诚表达不确定性的AI,却不会原谅信誓旦旦却给出错误答案的AI。
智能体工作流证据
AI智能体需要通过界面状态证明工作成果,而不只是描述付出的努力。优秀的智能体工作流会通过一系列检查点,让进度清晰可辨:计划已接受、来源已收集、编辑已应用、测试已运行、审核待处理,以及发布受阻或已就绪。
| 智能体状态 | 界面模式 | 重要性 |
|---|---|---|
| 规划 | 明确的目标和验收标准 | 防止智能体只追求活动量,而非实际成果 |
| 探索 | 附有置信度和时效性的来源列表 | 让用户能够区分已验证的事实与当前工作假设 |
| 执行 | 与检查点关联的文件变更摘要 | 无需阅读完整对话记录,也能审核编辑内容 |
| 验证 | 测试、路由、截图或运行时证据 | 将客观证明与人为营造的信心区分开来 |
| 发布 | 审批、部署或原生审核状态 | 防止发布流程用全部通过的本地检查掩盖尚未完成的工作 |
反面模式:用单一的“完成”状态表示多步骤智能体工作。复杂工作需要一条清晰可见的责任链:哪些内容发生了变化、哪些证据证明了结果、哪些事项被拒绝,以及哪些部分仍需人工判断。
Dieter Rams:十大原则
“少,却更好。”——Dieter Rams
Dieter Rams是20世纪最具影响力的工业设计师。1961年至1995年担任Braun设计主管期间,他创造的产品历经数十年仍不过时。他的作品直接启发了Apple的设计语言。
优秀设计的十大原则
1. 优秀的设计是创新的 不要照搬。应将不断进步的技术与创新设计相结合。
2. 优秀的设计让产品实用 每个元素都必须各司其职。形式追随功能。
3. 优秀的设计是美观的 美并非浮于表面,而是不可或缺。我们每天使用的产品会影响身心状态。
4. 优秀的设计让产品易于理解 用户不应需要说明书。界面本身就能引导使用。
5. 优秀的设计是克制的 设计应提供支持,而非喧宾夺主。用户的内容才是主角,而不是您的UI。
/* Obtrusive: UI competes with content */
.editor {
background: linear-gradient(135deg, purple, blue);
border: 3px dashed gold;
}
/* Unobtrusive: UI recedes, content shines */
.editor {
background: var(--color-background);
border: 1px solid var(--color-border);
}
6. 优秀的设计是诚实的 不要使用暗黑模式。不要过度承诺。应如实说明局限性。
7. 优秀的设计是经久耐用的 避免采用很快就会显得过时的潮流。经典胜过时髦。
TRENDY (will date): TIMELESS:
- Extreme glassmorphism - Clean typography
- Neon colors, glitch effects - Subtle elevation
- Aggressive gradients - Neutral palette with considered accent
8. 优秀的设计对每个细节都精益求精 任何细节都不应随意处理。加载状态、空状态、错误状态——一切都要经过设计。
9. 优秀的设计是环保的 性能关乎环境。尊重用户的注意力。编写高效代码。
10. 优秀的设计是尽可能少的设计 移除所有不必要的内容。最好的设计无形无迹。
2026 年 Web 模式
原生 CSS 如今可以取代 JavaScript,解决越来越多的布局与交互问题。2025 至 2026 年间,锚点定位、滚动驱动动画和 @starting-style 已进入正式版浏览器;到 2026 年年中,又新增了表单控件自动调整尺寸、间隙装饰和文本自动适配功能。
在此,支持状态比新颖程度更重要。仅在一个浏览器引擎中推出的功能应作为渐进增强;达到 Baseline Newly available 的功能则可放心作为开发基础。下表列出了截至 2026 年 8 月这两类功能的差异。
| 功能 | Chrome | Firefox | Safari | 状态 |
|---|---|---|---|---|
field-sizing |
123 | 152 | 26.2 | Baseline Newly available |
shape-outside: rect() / xywh() |
149 | 149 | 17.2 | Baseline Newly available |
background-clip: border-area |
150 | — | 18.2 | 两个引擎支持 |
间隙装饰(网格/弹性布局中的 column-rule) |
149 | — | — | 仅 Chrome |
text-fit |
150 | — | — | 仅 Chrome |
focusgroup |
150 | — | — | 仅 Chrome |
来源:web.dev 的 6 月 Web 平台新功能和7 月 Web 平台新功能。
容器查询
根据组件所在容器而非视口来调整其尺寸。
.card-grid {
container-type: inline-size;
container-name: card-grid;
}
.card {
display: grid;
gap: 16px;
padding: 20px;
}
@container card-grid (min-width: 400px) {
.card {
grid-template-columns: auto 1fr;
}
}
@container card-grid (min-width: 600px) {
.card {
padding: 32px;
gap: 24px;
}
}
:has() 选择器
根据子元素选择父元素——这在过去若不使用 JavaScript 根本无法实现。
/* Card with image gets different padding */
.card:has(img) {
padding: 0;
}
.card:has(img) .card-content {
padding: 20px;
}
/* Form group with error */
.form-group:has(.input:invalid) .form-label {
color: var(--color-error);
}
/* Highlight navigation when on that page */
.nav-item:has(a[aria-current="page"]) {
background: var(--color-surface);
}
CSS 嵌套
无需预处理器即可使用原生嵌套。
.card {
background: var(--color-surface);
border-radius: 12px;
padding: 24px;
& .card-title {
font-size: 1.25rem;
font-weight: 600;
margin-bottom: 8px;
}
& .card-body {
color: var(--color-text-secondary);
line-height: 1.6;
}
&:hover {
box-shadow: var(--shadow-md);
}
@media (min-width: 768px) {
padding: 32px;
}
}
间隙装饰
网格和弹性布局的间隙可以拥有自己的分隔线,因此无需再使用伪元素、为每个子元素添加边框,或为每列设置包装元素。此功能仅支持 Chrome 149 及更高版本,因而应作为渐进增强,而非基础功能。
.pricing-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 32px;
/* Vertical rules between columns, horizontal between rows */
column-rule: 1px solid var(--color-border);
row-rule: 1px solid var(--color-border);
}
旧方法会为除第一个项目外的所有项目添加 border-left,但网格一旦换行至第二行,效果便会出错。间隙装饰直接绘制在间隙中,因此换行后仍能保持正确。
由于目前仅有一个引擎支持,应将这些线条视为装饰,绝不能依赖它们区分内容含义。如果没有这些线条,布局就会变得含糊不清,那么该布局在 Firefox 和 Safari 中便会失效。
根据内容调整尺寸的表单控件
field-sizing: content 可让输入框、文本区域和选择框随用户输入的内容扩展或收缩,从而取代每个代码库都会重复实现的滚动高度 JavaScript。
.comment-box {
field-sizing: content;
min-height: 3lh; /* floor: three lines */
max-height: 12lh; /* ceiling: then scroll */
}
.tag-input {
field-sizing: content;
min-width: 8ch;
}
务必同时设置 min-/max- 边界。如果没有下限,空字段会收缩到几乎不可见;如果没有上限,粘贴长文本会把提交按钮挤出屏幕。
此功能于 2026 年 6 月达到 Baseline Newly available,因此可以放心将其作为主要机制,而非仅用于渐进增强。
自动适配容器的文本
text-fit 可缩放字体大小,使文本填满容器宽度,适用于展示型标题和仪表板大数字等以往需要测量脚本的场景。
.stat-value {
text-fit: consistent; /* one size for the whole box */
}
目前仅支持 Chrome 150。请先设置常规 font-size,让其他引擎获得精心设定的字号,而非默认值:
.stat-value {
font-size: clamp(2rem, 8vw, 6rem); /* the real answer everywhere */
text-fit: consistent; /* refinement where supported */
}
clamp() 已能解决人们在此处遇到的大多数问题,而且获得了普遍支持。只有当内容长度变化幅度过大、无法通过单一 clamp 方案处理时,才应考虑使用 text-fit。
无需变通方案的渐变边框
background-clip: border-area 可将背景绘制到边框区域,使渐变边框只需两行规则即可实现,无需使用嵌套元素或 mask-composite 技巧。
.featured-card {
border: 2px solid transparent;
border-radius: 12px;
background:
linear-gradient(var(--color-surface), var(--color-surface)) padding-box,
linear-gradient(135deg, #6366f1, #ec4899) border-area;
}
Chrome 150 和 Safari 18.2 支持此功能;Firefox 尚未推出。请先声明纯色 border-color,确保回退效果是一条真正的边框,而非透明边框。
无需 Keydown 处理程序的方向键导航
focusgroup 属性用于告知浏览器,一组控件构成一个键盘操作单元:按一次 Tab 进入该组,使用方向键在组内移动,再按 Tab 离开。工具栏、标签页栏、分段控件和单选按钮式按钮组都需要这种行为,而手工实现的组件最容易在这一点上出错。
<div role="toolbar" focusgroup="wrap">
<button>Bold</button>
<button>Italic</button>
<button>Underline</button>
</div>
wrap 会让用户在最后一个项目上按方向键时返回第一个项目。默认行为则会在两端停止。
目前仅支持 Chrome 150,因此在支持范围扩大前,请保留现有的 keydown 处理程序。现在了解此属性仍然很有价值,因为它准确描述了无障碍行为:工具栏应只有一个 Tab 停靠点,而非五个;这一要求比该属性早了数十年。ARIA 创作实践描述了这一模式,无论具体采用何种方式实现。
HTMX 集成
无需庞大的 JavaScript 框架即可实现服务器驱动的交互。
<!-- Load content on click -->
<button hx-get="/api/more-items"
hx-target="#item-list"
hx-swap="beforeend"
hx-indicator="#loading">
Load More
</button>
<!-- Form with inline validation -->
<form hx-post="/api/contact"
hx-target="#form-response"
hx-swap="outerHTML">
<input type="email" name="email"
hx-post="/api/validate-email"
hx-trigger="blur"
hx-target="next .error" />
<span class="error"></span>
</form>
锚点定位
使用原生 CSS 将一个元素相对于另一个元素定位——无需 JavaScript。适用于跟随触发元素的工具提示、弹出框和下拉菜单。
/* Anchor an element to another */
.trigger {
anchor-name: --my-trigger;
}
.tooltip {
position: fixed;
position-anchor: --my-trigger;
top: anchor(bottom);
left: anchor(center);
translate: -50% 8px;
}
滚动驱动动画
将动画进度与滚动位置关联。无需 JavaScript 即可实现阅读进度指示器、视差效果和渐显序列。
/* Reading progress bar */
.progress-bar {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 3px;
background: var(--color-primary);
transform-origin: left;
animation: progress linear;
animation-timeline: scroll();
}
@keyframes progress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
@starting-style
为进入 DOM 的元素定义初始样式——无需 JavaScript 即可实现仅依靠 CSS 的进入动画。
.card {
opacity: 1;
transform: translateY(0);
transition: opacity 0.3s ease, transform 0.3s ease;
@starting-style {
opacity: 0;
transform: translateY(10px);
}
}
Design Tokens 系统
一套完整的 token 系统,确保整个应用程序保持一致。
:root {
/* Colors */
--color-text: #1a1a1a;
--color-text-secondary: #666666;
--color-text-muted: #999999;
--color-background: #ffffff;
--color-surface: #f8f9fa;
--color-surface-elevated: #ffffff;
--color-border: #e5e7eb;
--color-primary: #3b82f6;
--color-primary-hover: #2563eb;
--color-success: #10b981;
--color-warning: #f59e0b;
--color-error: #ef4444;
/* Typography */
--font-sans: system-ui, -apple-system, sans-serif;
--font-mono: "SF Mono", Consolas, monospace;
--text-xs: 0.75rem;
--text-sm: 0.875rem;
--text-base: 1rem;
--text-lg: 1.125rem;
--text-xl: 1.25rem;
--text-2xl: 1.5rem;
--text-3xl: 2rem;
--leading-tight: 1.25;
--leading-normal: 1.5;
--leading-relaxed: 1.75;
/* Spacing (8px base) */
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */
--space-12: 3rem; /* 48px */
--space-16: 4rem; /* 64px */
/* Borders */
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
--radius-full: 9999px;
/* Shadows */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.07);
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
/* Transitions */
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
--duration-fast: 100ms;
--duration-normal: 200ms;
}
正确实现深色模式
不要只是反转颜色,而要针对深色环境重新设计。
@media (prefers-color-scheme: dark) {
:root {
/* Neutrals */
--color-background: hsl(220, 13%, 10%);
--color-surface: hsl(220, 13%, 15%);
--color-surface-elevated: hsl(220, 13%, 18%);
--color-border: hsl(220, 13%, 23%);
/* Text (inverted) */
--color-text: hsl(220, 9%, 93%);
--color-text-secondary: hsl(220, 9%, 70%);
--color-text-muted: hsl(220, 9%, 55%);
/* Adjust saturation for dark mode */
--color-primary: hsl(220, 80%, 60%);
--color-success: hsl(142, 70%, 45%);
--color-error: hsl(0, 80%, 65%);
/* Shadows in dark mode need adjustment */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.4);
}
}
深色模式原则: - 降低大面积表面的饱和度 - 提高强调色的明度 - 加深阴影(需要更强的对比度) - 有意识地设计深色模式,不要将其视为事后补救
Figma 提取工作流
要将设计文件转化为生产代码,需要系统地提取设计 tokens,包括定义设计语言的颜色、排版、间距和效果。
Figma Variables 导出
Figma 原生的 Variables 功能提供了最简洁的提取方式:
导出步骤:
1. 打开 Figma 文件→进入 Local Variables 面板并打开集合
2. 右键单击一个模式→“Export mode”(或右键单击集合→“Export modes”——每个模式会生成一个 JSON 文件)
3. 保存导出的文件,例如 figma-variables.json
Figma 的原生导出和导入功能都遵循 DTCG 格式——使用 $value/$type 键,并以 / 连接组名称;导入时也只接受采用这种结构的 tokens。
JSON Token 结构:
{
"colors": {
"primitive": {
"blue-500": { "$value": "#3b82f6", "$type": "color" },
"blue-600": { "$value": "#2563eb", "$type": "color" }
},
"semantic": {
"primary": { "$value": "{colors.primitive.blue-500}", "$type": "color" },
"primary-hover": { "$value": "{colors.primitive.blue-600}", "$type": "color" }
}
},
"spacing": {
"1": { "$value": "4px", "$type": "spacing" },
"2": { "$value": "8px", "$type": "spacing" },
"4": { "$value": "16px", "$type": "spacing" }
}
}
Token 到 CSS 的转换
CSS 自定义属性:
:root {
/* Primitive colors (direct values) */
--color-blue-50: #eff6ff;
--color-blue-100: #dbeafe;
--color-blue-500: #3b82f6;
--color-blue-600: #2563eb;
--color-blue-900: #1e3a8a;
/* Semantic colors (reference primitives) */
--color-primary: var(--color-blue-500);
--color-primary-hover: var(--color-blue-600);
--color-background: var(--color-white);
--color-surface: var(--color-gray-50);
/* Spacing (8px grid) */
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-4: 1rem; /* 16px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */
/* Typography */
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.125rem;
--line-height-tight: 1.25;
--line-height-normal: 1.5;
/* Effects */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.07);
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
}
深色模式 Tokens:
@media (prefers-color-scheme: dark) {
:root {
--color-background: var(--color-gray-900);
--color-surface: var(--color-gray-800);
--color-text: var(--color-gray-100);
--color-text-secondary: var(--color-gray-400);
/* Adjusted shadows for dark mode */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.4);
}
}
Token 到 SwiftUI 的转换
颜色扩展:
import SwiftUI
extension Color {
// MARK: - Primitive Colors
static let blue50 = Color(hex: "eff6ff")
static let blue500 = Color(hex: "3b82f6")
static let blue600 = Color(hex: "2563eb")
// MARK: - Semantic Colors
static let brandPrimary = Color.blue500
static let brandPrimaryHover = Color.blue600
// MARK: - Surface Colors
static let surfaceBackground = Color(light: .white, dark: Color(hex: "0f172a"))
static let surfaceElevated = Color(light: Color(hex: "f8fafc"), dark: Color(hex: "1e293b"))
}
extension Color {
init(hex: String) {
// Standard hex parsing implementation
}
init(light: Color, dark: Color) {
self.init(UIColor { traits in
traits.userInterfaceStyle == .dark ? UIColor(dark) : UIColor(light)
})
}
}
间距常量:
enum Spacing {
static let xs: CGFloat = 4 // --space-1
static let sm: CGFloat = 8 // --space-2
static let md: CGFloat = 16 // --space-4
static let lg: CGFloat = 24 // --space-6
static let xl: CGFloat = 32 // --space-8
}
// Usage
VStack(spacing: Spacing.md) {
// ...
}
.padding(Spacing.lg)
设计师交付检查清单
设计师应导出的内容:
| 资源类型 | 格式 | 备注 |
|---|---|---|
| 颜色 | Variables JSON | 包含浅色和深色模式 |
| 排版 | 样式导出 | 字体、字号、字重、行高 |
| 间距 | Variables JSON | 记录基础单位 |
| 图标 | SVG | 轮廓样式、单色 |
| 图片 | PNG @2x/@3x 或 WebP | 经过压缩 |
| 组件 | Figma 链接 | 供实现时参考 |
质量门槛标准:
- [ ] 所有颜色均定义为变量(无硬编码十六进制值)
- [ ] 排版使用已定义的文本样式
- [ ] 间距遵循网格系统(以 8px 为基础)
- [ ] 已提供深色模式变体
- [ ] 已记录交互状态(悬停、激活、禁用)
- [ ] 已标注响应式断点
- [ ] 已注明无障碍要求(对比度)
开发人员收到:
- Token 文件(根据平台提供 JSON/CSS/Swift)
- 包含尺寸标注的组件规范
- 采用所需格式导出的资源
- 交互文档(状态、动画)
- 无障碍标注
快速参考表
Gestalt 原则
| 原则 | 规则 | 用途 |
|---|---|---|
| 邻近性 | 相关元素应靠近 | 表单、区块 |
| 相似性 | 外观相同意味着功能相同 | 按钮、卡片 |
| 图形与背景 | 清晰分隔各层级 | 模态框、卡片 |
| 连续性 | 沿线条引导视线 | 时间线、对齐 |
| 闭合性 | 大脑会补全形状 | 图标、滚动提示 |
排版
| 元素 | 大小 | 字重 | 行高 |
|---|---|---|---|
| 正文 | 16px | 400 | 1.5-1.7 |
| 标题 | 24-48px | 600-700 | 1.1-1.2 |
| UI 标签 | 12-14px | 500 | 1.3-1.4 |
| 说明文字 | 12px | 400 | 1.4 |
颜色角色
| 角色 | 浅色模式 | 深色模式 |
|---|---|---|
| 背景 | #ffffff | #0f172a |
| 表面 | #f4f5f7 | #1e293b |
| 边框 | #e4e6ea | #334155 |
| 文本 | #1a1a2e | #f1f5f9 |
| 弱化文本 | #6b7280 | #94a3b8 |
| 主色 | #3b82f6 | #60a5fa |
| 成功 | #22c55e | #4ade80 |
| 错误 | #ef4444 | #f87171 |
间距比例
| Token | 值 | 用途 |
|---|---|---|
| –space-1 | 4px | 图标间距 |
| –space-2 | 8px | 行内元素 |
| –space-4 | 16px | 默认间距 |
| –space-6 | 24px | 卡片内边距 |
| –space-8 | 32px | 区块间距 |
| –space-16 | 64px | 页面区块 |
设计检查清单
发布任何界面之前,请确认:
Gestalt
- [ ] 相关元素之间的距离小于不相关元素(邻近性)
- [ ] 功能相似的元素采用相似样式(相似性)
- [ ] 前景与背景之间分隔清晰(图形与背景)
- [ ] 视线能自然地沿布局移动(连续性)
排版
- [ ] 基础字号至少为 16px
- [ ] 正文行高至少为 1.5
- [ ] 每行不超过 75 个字符
- [ ] 层级清晰(可区分 3 个层级)
- [ ] 全局使用一致的比例体系
颜色
- [ ] 所有文本均通过 4.5:1 对比度要求(WCAG AA)
- [ ] 颜色并非唯一的指示方式(同时使用图标或标签)
- [ ] 深色模式经过专门设计
- [ ] 遵循 60-30-10 配色比例
视觉层级
- [ ] 能够识别最重要的第 1 个元素
- [ ] 视线按预期顺序移动
- [ ] 每个区块只有一个明确的 CTA
- [ ] 字体比例保持一致
间距
- [ ] 所有间距均使用已定义的比例(无魔法数字)
- [ ] 卡片和组件的内边距保持一致
- [ ] 移动端间距舒适合理
- [ ] 网格对齐保持一致(以 8px 为基础)
交互
- [ ] 用户能否无需思考工具本身即可达成目标?
- [ ] UI 是否会适应当前情境?
- [ ] 工具是否仅在相关时显示?
- [ ] 重复使用是否能让用户掌握更高效的方法?
AI 界面
- [ ] 每项事实性陈述都有可追溯的来源
- [ ] 流式输出展示处理阶段,而不只是显示加载指示器
- [ ] 错误状态公开透明,不被隐藏
- [ ] 低置信度输出在视觉上有所区分
Dieter Rams 检查
- [ ] 是否还有可以移除的内容?
- [ ] 每个元素是否都服务于功能?
- [ ] 这套设计在 5 年后是否会显得过时?
- [ ] 是否设计了所有状态?
资源
书籍: - Sophie Lovell 著 As Little Design as Possible(Dieter Rams) - Robert Bringhurst 著 The Elements of Typographic Style
工具: - WebAIM 对比度检查器 - 字体比例生成器 - Figma Tokens Studio——设计 token 管理
设计系统: - Apple HIG - Material Design 3 - Radix UI - shadcn/ui
设计研究
深入剖析48款卓越产品,记录值得借鉴的模式与原则。
开发者工具与AI
| 产品 | 核心贡献 |
|---|---|
| Figma | 多人在线状态、上下文感知面板 |
| Warp | 基于块的终端、CLI-GUI桥接 |
| Framer | 可视化响应式设计、属性控件 |
| Vercel | 出色的深色模式、环境化状态提示 |
| Linear | 乐观式UI(Optimistic UI)、键盘优先工作流 |
| Raycast | 扩展系统、快捷操作 |
| Stripe | 卓越的文档、API设计 |
| Perplexity | 引用优先的AI、流式响应阶段 |
| Obsidian | 本地优先的可组合性、知识图谱界面 |
Apple原生与创意工具
| 产品 | 核心贡献 |
|---|---|
| Flighty | 15种智能状态、实时活动、数据可视化 |
| Halide | 智能激活、手势控制 |
| Bear | 排版优先、行内标签 |
| Craft | 原生优先的跨平台体验、嵌套页面 |
| Things | 延期日期、快速录入模式 |
| Darkroom | 沉浸式深色UI、照片优先编辑 |
| Procreate | 手势优先的创意工具 |
| Overcast | 将无形的音频工程化为界面设计 |
| Camo | 专业视频制作UI |
| Ivory | 精心打造的时间线、妙趣横生的精准设计 |
| Anybox | 平台原生的透明体验 |
| Drafts | 文本优先的清晰捕获体验 |
| Notion Calendar | 精准的日历体验、工作区集成 |
生产力、知识与金融
| 产品 | 核心贡献 |
|---|---|
| Superhuman | 100ms法则、命令面板训练、实践式引导 |
| Notion | 块系统、斜杠命令 |
| Arc | 空间、分屏视图、命令栏 |
| Todoist | 温暖的极简主义、最大程度的克制 |
| Amie | 愉悦的生产力体验、温暖的极简主义 |
| Loom | 亲切而专业的异步视频体验 |
| Pitch | 大胆鲜明的演示设计语言 |
| Readwise Reader | 深度阅读工具、宇宙风格品牌设计 |
| Copilot Money | 电影感十足的金融数据可视化 |
| 1Password | 化繁为简的安全体验 |
| Mercury | 电影般精致的银行体验 |
消费、社交与信任
| 产品 | 核心贡献 |
|---|---|
| Spotify | 色彩、情感与规模化设计 |
| Duolingo | 将游戏化融入设计语言 |
| Signal | 以简洁设计实现安全 |
| Airbnb | 大规模交易平台中的信任设计 |
| Bluesky | 算法透明度 |
| Letterboxd | 将电影转化为社交对象 |
| Strava | 将GPS数据转化为社交资本 |
| Apple Music | 编辑化表达、空间音频 |
| Headspace | 将平静作为界面策略 |
| Zomato | 由个性驱动的餐饮UX |
实体产品、游戏与无障碍设计
| 产品 | 核心贡献 |
|---|---|
| Balatro | 反馈循环、游戏手感系统 |
| Rivian | 探险摄影与恢宏的字体设计 |
| Teenage Engineering | 将约束塑造为美学身份 |
| OKO | 音频与触觉无障碍体验 |
| CARROT Weather | 以鲜明个性实现工具类应用的差异化 |
本指南在实践中不断完善。设计原则历久弥新,其应用方式则随着技术进步与认知深化持续演变。