Guide / 17 min

面向软件工程师的设计原则

学习构建更优软件所需的设计基础,涵盖字体排印、色彩理论、间距、动画、AI界面模式,以及从Arc到Zomato的48个产品案例研究。

更新于2026年5月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等产品的界面。这份指南凝练了这些理解,成为我刚开始在意软件外观与体验时,曾希望拥有的完整参考。

设计不是装饰,而是沟通。每一个像素都在传达功能、层级和意义。业余感软件与专业感软件之间的差别,在于是否理解这些原则,并能一以贯之地应用它们。

本指南假定您已经会编写代码。它教会您“看见”:理解为什么有些界面让人感觉毫不费力,而另一些却显得杂乱无章;更重要的是,学会如何构建前者。


目录

第一部分:基础理论

  1. Gestalt 心理学
  2. 字体排印
  3. 色彩理论
  4. 视觉层级
  5. 间距与节奏
  6. 动效原则

第二部分:交互与 AI

  1. 交互模式
  2. AI 界面模式

第三部分:设计哲学

  1. Dieter Rams:十大原则

第四部分:实现

  1. 2026 Web 模式
  2. Design Tokens 体系
  3. 暗色模式的正确实现
  4. Figma 导出工作流

第五部分:参考

  1. 速查表
  2. 设计清单
  3. 设计案例研究

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("[email protected]", 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 大幅运动(页面过渡、模态框) 沉稳从容

性能:黄金法则

只对 transformopacity 做动画 — 它们经过GPU加速,不会触发布局重排。

/* BAD: Animating layout */
.panel { transition: left 0.3s, width 0.3s; }

/* GOOD: Using transform */
.panel { transition: transform 0.3s; }

何时不该使用动画

  1. 用户启用了 prefers-reduced-motion css @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } }

  2. 动画不传达任何信息 — 多余的旋转、弹跳元素

  3. 用户赶时间 — 错误状态、表单验证、搜索结果
  4. 动画会拖慢重复操作 — 键盘快捷键应跳过动画
  5. 数据已加载完毕 — 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出错或不确定时,应清晰展示,不要躲在听起来很自信的文字后面。

情况 不佳模式 良好模式
置信度低 自信地陈述 “我不确定,但……”并使用较弱的样式
未找到来源 编造文本 “我找不到支持这一说法的来源”
来源相互矛盾 默默选择其中一个 同时展示两者,并突出冲突点
信息过时 当作当前信息呈现 “截至[date]……”并附带时效性指示
关键洞察:用户会原谅诚实表达不确定性的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模式

现代Web设计利用原生CSS能力,在许多情况下不再需要JavaScript。2025-2026年,anchor positioning、滚动驱动动画和@starting-style已进入生产浏览器。

容器查询

根据组件所在容器而非视口来确定组件尺寸。

.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;
  }
}

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);
  }
}

设计 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. 点击集合菜单→“导出为JSON” 3. 保存为figma-variables.json

JSONToken结构:

{
  "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转换

CSSCustom Properties:

: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的转换

Color扩展:

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)

设计师交接清单

设计师应导出的内容:

资产类型 格式 备注
颜色 变量 JSON 包含浅色模式和深色模式
排版 样式导出 字体、字号、字重、line-height
间距 变量 JSON 记录基础单位
图标 SVG 轮廓样式,单色
图片 PNG @2x/@3x或WebP 经过压缩
组件 Figma链接 供实现时参考
质量门禁标准:
  • [ ] 所有颜色均定义为变量(不使用硬编码十六进制色值)
  • [ ] 排版使用已定义的文本样式
  • [ ] 间距遵循网格系统(以8px为基础)
  • [ ] 提供深色模式变体
  • [ ] 记录交互状态(hover、active、disabled)
  • [ ] 标注响应式断点
  • [ ] 注明无障碍要求(对比度比例)

开发者收到:

  1. token文件(JSON/CSS/Swift,具体取决于平台)
  2. 带测量值的组件规格
  3. 所需格式的资产导出
  4. 交互文档(状态、动画)
  5. 无障碍标注

快速参考表

Gestalt原则

原则 规则 用途
接近性 相关内容=靠近 表单、分区
相似性 外观相同=功能相同 按钮、卡片
图底关系 清晰的层级分离 Modal、卡片
连续性 沿线条延续 时间线、对齐
闭合性 大脑会补全形状 图标、滚动提示
### 排版
元素 尺寸 字重
--------- ------ --------
正文 16px 400
标题 24-48px 600-700
UI标签 12-14px 500
说明文字 12px 400
### 颜色角色
角色 浅色模式 深色模式
------ ------------ -----------
背景 #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年后会不会显得过时?
  • [ ] 我是否已经设计了每一种状态?

资源

书籍: - As Little Design as Possible,作者Sophie Lovell(Dieter Rams) - The Elements of Typographic Style,作者Robert Bringhurst

工具: - WebAIM Contrast Checker - Type Scale Generator - Figma Tokens Studio — 设计tokens管理

设计系统: - Apple HIG - Material Design 3 - Radix UI - shadcn/ui


Design 研究

深入剖析48款出色产品,记录值得借鉴的模式与原则。

开发者工具与AI

产品 核心贡献
Figma 多人协作在线感知、上下文感知面板
Warp 基于块的终端、CLI-GUI桥接
Framer 可视化响应式设计、属性控件
Vercel 出色的深色模式、环境化状态
Linear Optimistic UI、键盘优先工作流
Raycast 扩展系统、快速操作
Stripe 出色的文档、API设计
Perplexity 引用优先的AI、流式阶段
Obsidian 本地优先的可组合性、知识图谱界面
### Apple 原生与创意工具
产品 核心贡献
--------- ------------------
Flighty 15种智能状态、Live Activities、数据可视化
Halide 智能激活、手势控件
Bear 以排版为核心,内联标签
Craft 原生优先的跨平台体验,嵌套页面
Things 延期日期,快速录入模式
Darkroom 沉浸式深色UI,以照片为核心的编辑
Procreate 手势优先的创作工具
Overcast 将不可见的音频工程转化为界面设计
Camo 专业视频制作UI
Ivory 时间线打磨,精巧而有趣
Anybox 平台原生的透明感
Drafts 文本优先的捕捉清晰度
Notion Calendar 日历精确性,工作区集成
### 生产力、知识与财务
产品 关键贡献
--------- ------------------
Superhuman 100ms规则、命令面板训练、练习式引导
Notion 块系统、斜杠命令
Arc Spaces、分屏视图、命令栏
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 将个性作为工具类应用的差异化手段

本指南在实践中不断完善。设计原则历久弥新,但其应用会随着技术和理解不断演进。