/ Guide / 21 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歸納出的錯誤透明度)。將網頁模式更新至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. 正確實作 Dark Mode
  4. Figma 設計稿匯出流程

第五部分:參考資源

  1. 快速參考表
  2. 設計檢核清單
  3. 設計案例研究

Gestalt 心理學

「整體不同於各部分的總和。」— Kurt Koffka

Gestalt 心理學發源於 1920 年代的德國,旨在解釋人類如何感知視覺資訊。大腦並非逐一辨識像素,而是將元素組織成有意義的模式。掌握這些原則,便能主導使用者對介面的認知方式。

鄰近性(Proximity)

彼此靠近的元素會被視為一組。

這是 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

相似性(Similarity)

具有相同視覺特徵的元素會被認為彼此相關。

當元素外觀一致時,使用者會假設它們的功能也相同。這正是設計系統採用一致按鈕樣式、卡片處理方式和字型排版的原因。

Example Navigation:
┌───────────────────────────────────┐
 [Dashboard] [Projects] [Settings]    Same style = same function
                                   
 ┌─────┐  ┌─────┐  ┌─────┐        
 Card   Card   Card             Same style = same content type
 └─────┘  └─────┘  └─────┘        
                                   
 [+ New Project]                      Different style = different function
└───────────────────────────────────┘

圖地關係(Figure-Ground)

內容應與背景明確區隔。

大腦需要區分「圖」(聚焦對象)與「地」(背景)。圖地關係處理不當會造成視覺混亂。

常用手法: - 對比(淺色圖形搭配深色背景,或反之) - 陰影(將圖形提升至背景之上) - 邊框(界定圖形邊緣) - 模糊(模糊背景、銳化前景)

/* 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 */
}

共同區域(Common Region)

位於同一邊界內的元素會被視為同一群組。

將元素包圍在視覺容器中(卡片、方框、邊框區域),即暗示它們彼此關聯。

連續性(Continuity)

視線會自然沿著路徑、線條與曲線移動。

善用對齊與視覺動線,引導使用者的注意力流動於介面之中。

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
└────────────────────────────────┘

封閉性(Closure)

大腦會自動補全不完整的形狀。

使用者不需要看到每一個像素——他們會在腦中自動補完熟悉的形狀。這使得更簡約、更優雅的設計成為可能。

/* 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

字型排版是介面設計的根基。文字傳遞功能、層級與品牌特質。拙劣的排版讓介面更難使用;出色的排版則渾然天成——使用者甚至察覺不到它的存在。

字級系統(Type Scale)

一致的字級系統能營造視覺和諧感,建議採用數學比例來建構。

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 */
}

行高(Leading)

行高對可讀性影響甚鉅,不同類型的內容需要不同的行距設定。

內容類型 行高 原因
標題 1.1 - 1.2 緊湊、粗體、篇幅短
UI 文字 1.3 - 1.4 標籤、按鈕
內文 1.5 - 1.7 確保段落的可讀性
長篇閱讀 1.7 - 2.0 文章、技術文件

行寬(Measure)

最佳行寬能減少視覺疲勞,提升閱讀理解力。

  • 最佳範圍:每行 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用途
藍色 信任、穩定、平靜 金融、科技、企業
綠色 成長、自然、成功 健康、環保、正向狀態
紅色 活力、緊迫、危險 警示、銷售、錯誤
橘色 溫暖、熱情 CTA、活潑品牌
黃色 樂觀、警戒 警告、重點提示
紫色 奢華、創意 高階產品
### 深色模式優先設計(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表示這兩項標準將會並存。無障礙指南工作小組計畫在2026年發布預估的WCAG 3時程,但目前的工作仍應以WCAG 2.2為目標標準。

工具:WebAIM Contrast Checker、Chrome DevTools色彩選擇器


視覺層級

「設計是品牌的無聲大使。」——Paul Rand

視覺層級控制使用者第一眼、第二眼、第三眼會看到什麼。缺乏清楚層級時,使用者必須費心尋找資訊。有了明確層級,介面就會顯得毫不費力。

視覺層級的6項工具

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): 航班進度視覺化呼應實體航空儀表:高度曲線、速度指示器與登機門地圖,都使用熟悉的視覺隱喻,而非抽象的進度列。

瞇眼測試

瞇眼看您的設計。仍然看得出層級嗎?如果看得出來,就表示層級夠明確。


間距與節奏

「Whitespace就像空氣:設計需要它,才能呼吸。」——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)

模式切換應該徹底改變介面,而非僅僅切換元素的顯示與隱藏。Halide 的自動模式和手動模式是截然不同的兩套介面。Warp 透過四種輸入方式(打字、指令面板、AI、滑鼠)巧妙地橋接了CLI與圖形介面,不強迫使用者侷限於單一操作範式。

結構化內容(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 兩個引擎
間隙裝飾(grid/flex 中的 column-rule 149 僅限 Chrome
text-fit 150 僅限 Chrome
focusgroup 150 僅限 Chrome

來源:web.dev 的六月 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;
  }
}

間隙裝飾

Grid 與 flex 的間隙如今可以套用專屬線條,因此分隔線不再需要偽元素、為每個子元素加上框線,或為每欄建立包裝元素。此功能僅支援 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,但只要 grid 換行至第二列,版面便會出錯。間隙裝飾直接繪製在間隙內,因此換行後仍能維持正確效果。

由於目前僅有單一引擎支援,請將這些線條純粹視為裝飾,切勿用來區分內容含義。若缺少線條便會導致版面語意不清,那麼這個版面在 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 Authoring Practices 都對此模式有所說明。

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(Dieter Rams)著作《As Little Design as Possible》 - 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 以鮮明個性打造實用工具App的差異化

本指南在實踐中持續成長。設計原則歷久彌新,其應用方式則隨著技術與認知不斷演進。