/ Guide / 20 min

软件工程师设计原则

面向软件工程师的设计基础:涵盖排版、色彩、间距、动画、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等产品的界面。本指南将这些理解提炼成一份全面的参考资料——这正是我刚开始重视软件外观与体验时,希望能够读到的指南。

设计不是装饰,而是沟通。每一个像素都在传达功能、层级与含义。业余软件与专业软件之间的差别,在于是否理解这些原则,并始终如一地加以运用。

本指南假定您已经能够编写代码。它将教会您如何观察——理解为何有些界面用起来毫不费力,而另一些却杂乱无章;更重要的是,掌握如何构建前者。


目录

第一部分:基础理论

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

性能:黄金法则

只对 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失败或无法确定时,应明确展示情况,而非用貌似自信的文字加以掩饰。

情况 不良模式 良好模式
置信度低 以肯定语气陈述 使用较弱的视觉样式显示“我无法确定,但……”
未找到来源 编造内容 “我无法为此陈述找到来源”
来源相互矛盾 不作说明地选择其一 同时展示双方,并突出显示冲突之处
信息已过时 当作当前信息呈现 显示“截至[日期]……”,并附上时效性指示器

关键洞见:用户会谅解坦诚表达不确定性的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 为基础)
  • [ ] 已提供深色模式变体
  • [ ] 已记录交互状态(悬停、激活、禁用)
  • [ ] 已标注响应式断点
  • [ ] 已注明无障碍要求(对比度)

开发人员收到:

  1. Token 文件(根据平台提供 JSON/CSS/Swift)
  2. 包含尺寸标注的组件规范
  3. 采用所需格式导出的资源
  4. 交互文档(状态、动画)
  5. 无障碍标注

快速参考表

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 以鲜明个性实现工具类应用的差异化

本指南在实践中不断完善。设计原则历久弥新,其应用方式则随着技术进步与认知深化持续演变。