颜色使用模式
颜色使用模式回答“这个背景、标题、hover、选中、边框应该用哪个 token”。它补充 Design Tokens 标准:token 文档说明有哪些颜色语义,本页说明如何按场景选择。
选择顺序
为一个组件区域选颜色时,按下面顺序判断:
- 先判断区域层级:window、panel、control、popup、navigation、data chrome、overlay。
- 再判断交互语义:normal、hovered、pressed、focused、selected、disabled。
- 再判断业务语义:primary、success、warning、danger。
- 最后处理组合状态:selected + hover、focused + selected、error + focused。
不要先从视觉偏好出发挑颜色。先确定语义,再选 token。
背景选择
| 场景 | 默认背景 | 说明 |
|---|---|---|
| 应用窗口、工作台底色 | surfaceWindow |
最大面积底色,承载页面和工作区。 |
| 页面区块、卡片、工具面板内容区 | surfacePanel |
比 window 更像内容容器。 |
| 普通按钮、输入框、下拉框 | surfaceControl |
可交互控件默认背景。 |
| 控件 hover | surfaceControlHover |
指针位于可交互控件上。 |
| 控件 pressed | surfaceControlActive |
指针或键盘正在激活控件。 |
| 弹出菜单、Dropdown popup、ContextMenu、Tooltip 容器 | surfacePopup |
脱离普通布局层的临时浮层。 |
| 导航栏、菜单栏、工作区 tab strip、auto-hide rail | surfaceNav |
用于承载导航入口或工作区 chrome。 |
| 表格表头、数据分组头、字段列表头 | surfaceDataHeader |
数据区域的标题和结构 chrome。 |
| 弱选中背景 | selectionMuted |
active tab、当前导航项、弱激活面板。 |
| 强选中背景 | selectionBg |
表格选中行、强激活项、需要明确识别的当前项。 |
判断规则:
- 大面积背景优先用
surfaceWindow或surfacePanel,不要用 accent 色。 - 可点击控件的 hover/pressed 使用 control 状态色,不要直接用
accentPrimary铺底。 - 导航、tab strip、dock rail 属于 chrome,不属于内容区,优先用
surfaceNav。 - 数据表头和分组头属于数据结构 chrome,优先用
surfaceDataHeader。 - selected 必须比 hover 更明确;hover 不能覆盖 selected。
文本和图标颜色
| 场景 | 推荐 token | 说明 |
|---|---|---|
| 主标题、主要内容 | textPrimary |
默认可读文本。 |
| 辅助说明、弱标签、未激活图标 | textSecondary |
弱于正文但仍可读。 |
| 禁用文本或禁用图标 | textDisabled |
不可操作状态。 |
| 强调链接、active 图标、主操作文本 | textAccent 或 accentPrimary |
只用于需要强调的入口。 |
| accent 背景上的文本 | textOnAccent |
primary/selected 强背景上使用。 |
| danger 背景上的文本 | textOnDanger |
danger 强背景上使用。 |
规则:
- 图标默认跟随文本语义,不单独发明颜色。
- 普通图标按钮 normal 状态通常用
textSecondary。 - hover/pressed 可以把图标增强为
textPrimary或accentPrimary,但不要同时给强底色和强图标,除非它是 selected/primary/danger。 - disabled 图标必须使用
textDisabled。
边框和焦点
| 场景 | 推荐 token | 说明 |
|---|---|---|
| 弱分隔线、pane 非激活边框 | borderSubtle |
不抢视觉层级。 |
| 普通控件边框 | borderControl |
输入框、按钮、下拉框等。 |
| 控件 hover 边框 | borderControlHover |
hover 时比普通边框更明确。 |
| 数据区域边框 | borderData |
表格、树表、数据网格。 |
| 数据区域强调边框 | borderDataStrong |
当前列、当前区域、强分隔。 |
| 键盘焦点框 | focusBorder |
只表达 focus,不改变布局尺寸。 |
规则:
- focus ring 不是 selected,也不是 hover;不要用 focus ring 代替 active 状态。
- 同一区域不要叠加多条同色边框。
- active pane 可以使用
focusBorder或 selected 类 token,但文档要说明它表达的是 active pane,不是键盘焦点。
状态组合
| 组合 | 规则 |
|---|---|
| normal + hover | 背景从默认 surface 切到 hover surface。 |
| hover + pressed | pressed 优先,使用 active surface。 |
| selected + hover | selected 保持主视觉,hover 只做轻微增强。 |
| focused + selected | selected 表达当前项,focus ring 额外绘制,不改变 selected 背景。 |
| disabled + any | disabled 优先,清理 hover/pressed,并使用 disabled 文本。 |
| error + focused | error 边框或提示保留,focus ring 可叠加但不能遮掉 error。 |
示例:IconButton
IconButton 是最容易被画重的控件。标准模式:
| 状态 | 背景 | 图标 | 边框 |
|---|---|---|---|
| normal | 透明或不绘制 | textSecondary |
无 |
| hovered | surfaceControlHover |
textPrimary 或 accentPrimary |
可无 |
| pressed | surfaceControlActive |
accentPrimary |
可无 |
| selected | selectionMuted |
accentPrimary |
可用 accentPrimary 弱强调 |
| disabled | 透明或不绘制 | textDisabled |
无 |
判断:
- 普通工具按钮 normal 状态不应像 selected。
- hover 才出现浅底。
- pressed 是短反馈,不改变按钮尺寸。
- 如果图标不容易理解,必须配 tooltip。
DockWorkbench 的 pin 按钮属于这个模式:默认只画 pin icon,hover/pressed 才画浅底;它不是 primary button。
示例:Tab
Tab 同时有 chrome、selected、hover、close action。
| 区域 / 状态 | 推荐颜色 |
|---|---|
| tab strip 背景 | surfaceNav |
| inactive tab 背景 | 透明或 surfaceNav |
| inactive tab hover | surfaceControlHover |
| active tab 背景 | surfacePanel 或 selectionMuted |
| active tab 强调线 | accentPrimary |
| tab 文本 | active 用 textPrimary,inactive 用 textSecondary |
| close 按钮 normal | 图标 textSecondary,背景透明 |
| close 按钮 hover | 背景 surfaceControlHover,图标 textPrimary |
判断:
- active tab 必须比 hover 更明确。
- close 按钮不应在 normal 状态抢过 tab title。
- 文档 tab 可使用 overflow menu;工具区 tab 窄宽时优先保留 icon strip。
示例:Pane 和标题栏
Pane 是内容区域和 chrome 的组合。
| 区域 / 状态 | 推荐颜色 |
|---|---|
| pane body | surfacePanel 或 surfaceWindow,按是否是内容容器决定。 |
| pane header | surfaceNav 或 surfaceDataHeader,按导航/数据语义决定。 |
| inactive pane border | borderSubtle |
| active pane border | focusBorder 或 selectionBg 的弱表达 |
| splitter | borderSubtle |
| splitter hover/drag | borderControlHover 或 accentPrimary 的弱表达 |
判断:
- header 只是结构 chrome,不应默认使用强 accent 背景。
- active pane 可以有更强边框,但不要让 hover、focus、active 都只靠同一条边框表达。
- splitter 的可拖拽 hit rect 可以比视觉线更宽,但视觉线要稳定。
示例:Popup 和 ContextMenu
Popup 脱离普通布局层,要和页面内容分开。
| 区域 / 状态 | 推荐颜色 |
|---|---|
| popup container | surfacePopup |
| popup border | borderSubtle 或 popup 专用边框 token |
| menu item normal | 透明或 surfacePopup |
| menu item hover | surfaceControlHover |
| menu item pressed | surfaceControlActive |
| disabled menu item | 文本 textDisabled,无 hover action |
| destructive item | 文本或 icon 使用 accentDanger,不默认铺 danger 背景 |
判断:
- Popup 不应使用 page surface,否则层级不清。
- ContextMenu 命令的 disabled 状态必须来自当前 selection、权限和 placement。
- destructive 菜单项只在确认类强动作中使用 danger 背景;普通右键菜单通常只让文字或图标变 danger。
示例:Auto-hide Rail
Auto-hide rail 是工作台边栏,不是浮动按钮。
| 区域 / 状态 | 推荐颜色 |
|---|---|
| rail 背景 | surfaceNav |
| rail border | borderSubtle |
| inactive rail tab | 透明或 surfaceNav |
| rail tab hover | surfaceControlHover |
| active rail tab | selectionMuted |
| rail tab 文字 | inactive 用 textSecondary,active 用 accentPrimary |
| rail tab icon | 跟随文字颜色 |
判断:
- rail 参与布局,应和 tab strip / navigation chrome 同层。
- rail tab hover 是可点击入口反馈,不应画成深色 floating button。
- left/right rail 的竖排文字仍要保持可读;宽度不足时优先保留图标和关键文本。
示例:Dock Guide
Dock guide 是拖拽辅助,不是常驻控件。
| 区域 / 状态 | 推荐颜色 |
|---|---|
| preview 背景 | selectionMuted 的半透明派生 |
| preview 边框 | accentPrimary |
| guide cluster 背板 | surfacePopup 或高层 overlay surface |
| inactive guide button | surfacePanel 或 surfacePopup |
| active guide button | selectionBg |
| guide icon | inactive 用 textPrimary,active 用 textOnAccent |
判断:
- preview 应接近最终 dock 区域,不能只画一个模糊方向提示。
- workbench edge guide、document-area guide、pane guide 可以有不同尺寸,但颜色语义应一致。
- 拖拽结束后 guide 状态必须清理。
反例
不要这样做:
- 普通 icon button normal 状态直接画强蓝底。
- auto-hide rail 画成浮在内容上的深色按钮。
- hover 后增加 padding 或边框导致布局跳动。
- active、hover、focus 全部只用同一条蓝色边框表达。
- Popup 使用页面背景,导致浮层和内容区层级不清。
- Dock guide 使用随机硬编码蓝色,却没有说明它来自 selected/primary 语义。
- disabled 只阻断事件但仍使用 normal 文本和 hover 背景。
如果找不到合适 token,先判断是否缺少组件级 token;不要临时挑一个“看起来差不多”的颜色长期留在组件里。