一套可计算的界面设计规范

本文展示如何把色彩、对比度、色阶、设计令牌、组件状态与交付校验整理成一套可复用的界面规则。

适用范围:文中品牌色、色阶和尺寸令牌是一套计算示例,不是本资料库网站或 words-app-yunxiao 的现行主题配置。应用到具体项目时,应以目标项目的本地约定和全局令牌为准;本资料库站点的样式令牌定义在 public/assets/site.css。words-app-yunxiao 的实践提示还应核对现有页面状态和多端交互,不能只验算令牌表;执行要点见界面基础规范。

来源:个人知识库《一套可计算的界面设计规范》(UI 设计规范 v1.0)。

项目 规格
版本 v1.0
品牌色 4 个 / 2 族
色阶 每条 10 级
中性色阶 12 级
圆角令牌 5 档
对比度依据 WCAG 2.1

从四个品牌色到一个完整令牌体系 —— 每一个数值都可追溯、可复现、可被下一个执行者直接使用。

00 文档说明

这份文档描述的不是一版视觉稿,而是一套可被复用的规则。它的每一个数值都可以被追溯、被计算、被验证 —— 颜色为什么只能是这四个、圆角为什么只有五档、层级为什么不能用阴影,本文都给出可核对的依据,而不是「这样比较好看」。

全文共 13 个章节,分为三层:价值层(§01 原则)、系统层(§02–§07 色彩与令牌)、执行层(§08–§12 组件、检查与复用)。若只有 5 分钟,读 §01 与 §11;若要动手实现,直接进 §06 与 §12。

阅读路径 决策者:§01 设计原则 → §02.5 角色分配 → §11 跨项目复用。
设计师:§02 色彩系统 → §03 色阶推演 → §05 渐变规范 → §07 层级表达。
前端:§04 中性色阶 → §06 设计令牌 → §08 组件规范 → §12 交付检查清单。

文档约定

  • 所有色值采用 #RRGGBB 大写十六进制,不使用 rgba()、hsla() 或任何带透明通道的写法。
  • 对比度一律按 WCAG 2.1 相对亮度公式计算,标注格式为 数值:1。分级含义:AAA ≥ 7:1,AA ≥ 4.5:1,AA·大字 ≥ 3:1(仅限 ≥24px 常规或 ≥18.66px 粗体)。
  • 「档位」指 10 级色阶中的位置,本系统用 50 / 100 / … / 900 标记,数值越小越浅。
  • 本文档界面遵守其定义的禁则;键盘焦点通过令牌色块保持可见,见 §09.2。

01 设计原则

以下五条不是风格偏好,是约束。约束与偏好的区别在于:约束可以判定违反与否,偏好只能争论。这五条里没有一条提到「好看」。

原则一 · 先定约束,再定风格

风格是约束的结果,不是起点。当有人提出「我想要蓝色加粉色」时,讨论必然滑向审美判断;当陈述改为「现有做法会随内容增长而失控」时,讨论才进入逻辑判断。所有视觉决策都应能回答同一个问题:它约束了什么?

原则二 · 层级用明度差与色块表达

模块层级优先使用相邻明度差与色块拼接。阴影禁用,描边不表达层级、选中或焦点;只有相邻两面没有可用明度差、又确实需要标明边界时,才使用令牌 --line-subtle。

原则三 · 颜色角色由对比度决定,不由审美决定

一个颜色能承担什么角色,取决于它压在白底上的对比度数值。过 7:1 才能做正文,过 4.5:1 能做小字,3:1 只能做大字与按钮,低于 3:1 就只能做装饰。先算,再分配。本系统中藏青之所以是主色,唯一原因是它 9.61:1,是四色中唯一能承载正文的。

原则四 · 令牌唯一,不留自由值

任何视觉值都必须来自令牌表。出现一个 13px 的字号或 10px 的圆角,就意味着系统出现了漏洞。令牌化的目的不是整洁,是可交接 —— 下一个执行者不需要问「这里该用多少」。

原则五 · 强调色的价值来自它的稀缺

强调色一旦铺开就失效。玫红在本系统中的每一次出现都对应一个明确的动作或重点,出现频率约占总面积的 3% 以下。这是刻意控制的配额,不因「这里有点空」而调高。

一句话总纲 用可计算的规则替代不可争论的审美。规则一旦成立,后续任何人照着做都能得到一致结果,不需要再回到「好不好看」这个无法收敛的问题上。

02 色彩系统

先给结论:这四个色不是四个独立色,而是两族颜色。冷色族两个(藏青、青蓝),粉族两个(玫红、浅粉)。每一族都是一「深」一「浅」,浅色从深色派生而来。这是这套配色看起来成套的根本原因,也是它可被复用的前提。

2.1 品牌色定义

四色之外,本系统不引入任何第五个色相。全部界面的色彩表达由这四色加一条中性灰阶完成。

  • 结构色 · 藏青 — #0D3D9F;RGB 13 61 159;HSL 220.3° 84.9% 33.7%;明度档位 700;白底对比 9.61:1
  • 强调色 · 玫红 — #F7226F;RGB 247 34 111;HSL 338.3° 93.0% 55.1%;明度档位 500;白底对比 3.88:1
  • 装饰色 · 青蓝 — #0DAACD;RGB 13 170 205;HSL 190.9° 88.1% 42.7%;明度档位 600;白底对比 2.75:1
  • 装饰色 · 浅粉 — #F88EC6;RGB 248 142 198;HSL 328.3° 88.3% 76.5%;明度档位 200;白底对比 2.17:1

命名纠正 玫红常被误称为「鲑红」。#F7226F 的色相是 338.3°,属于偏冷的品红;鲑红(salmon)大致落在 6° 附近,是橙粉。两者相差一个色温区。命名精确在色彩工作里不是修辞问题 —— 它决定了后续推导方向:从 338.3° 往浅走得到浅粉,从 6° 往浅走得到蜜桃色,是完全不同的结果。

2.2 色相结构:两族,不是四个

把四个色的色相角排到色环上,结构立刻显现:

  • 冷色族:藏青 220.3° 与青蓝 190.9°,相差 -29.4° —— 属于邻近色关系,不是同一色也不构成对比色。
  • 粉族:玫红 338.3° 与浅粉 328.3°,相差 10.0° —— 这已经不是「邻近」,而几乎是同一色相。

这意味着浅粉并不是一个独立选择的粉色,它就是玫红提亮后的版本;青蓝也不是一个独立的蓝,它是藏青沿色环偏移 -29.4° 后的邻近色。辅色有出处,所以不打架。

可验证的判据 把两个「辅色」单独拿出来问:「它从哪个主色派生出来的?」如果答不上来,这个辅色就是错的,无论它看起来多合适。本条判据在 §11 的复用配方里会再次用到。

2.3 饱和度约束:全系统收敛在 84–93%

这是整套配色最容易被忽略、却最关键的一条。四个色的饱和度分别为:

颜色 色相 H 饱和度 S 明度 L 与基准的差距
藏青 220.3° 84.9% 33.7% 0.0 个百分点
玫红 338.3° 93.0% 55.1% 8.1 个百分点
青蓝 190.9° 88.1% 42.7% 3.2 个百分点
浅粉 328.3° 88.3% 76.5% 3.4 个百分点

全部落在 84.9% – 93.0% 这个极窄的区间内,极差仅 8.1 个百分点。这是「高级感」的真正来源:色相可以拉得很开,饱和度必须齐。

最常见的一种破坏 只要把其中任意一个色的饱和度降到 40% 左右(例如常见的莫兰迪灰蓝),整套配色会立刻显得拼凑。原因是其余三色仍在 85% 以上,唯一那个低饱和色会被读成「没调好」,而不是「刻意柔和」。若要降低整体饱和度,必须四个一起降,保持极差不变。

2.4 明度阶梯与档位锚定:四色分处四个不重叠的明度带

把明度轴切成一架 10 级阶梯,四个品牌色精确落在四个不同档位上,彼此不重叠。这不是巧合,是这套配色能同时容纳四色而不混乱的结构性原因 —— 它们压根不在同一个明度区间里竞争。

颜色 明度 L 锚定档位 偏差 所处明度带
藏青 33.7% 700 0.0 暗
青蓝 42.7% 600 0.0 中暗
玫红 55.1% 500 0.0 中亮
浅粉 76.5% 200 0.0 亮

明度依次为 33.7% → 42.7% → 55.1% → 76.5%,相邻间隔 9.0 / 12.4 / 21.4 个百分点,呈递增排列。间隔之所以递增,是因为人眼对亮部差异的分辨力弱于暗部 —— 亮区需要更大的明度跨度才能产生同等程度的「不同感」。四个色之所以看起来层次分明,正是因为它在暗端收得紧、亮端放得开。

为什么这条重要 很多配色方案失败的原因不是颜色选得难看,而是四个色挤在同一条明度带上。挤在一起就必然争夺同一角色,最终只能靠加大面积或加饱和度来强行区分,结果就是页面花。本系统在数值层面就已经把四个色的位置错开了。

2.5 对比度与角色分配:角色是算出来的

明度差直接决定对比度,对比度直接决定这个色能用在哪里。下表是四个色压在白底(#FFFFFF)上的实测值:

颜色 色值 压白底对比度 白底等级 白色压它 系统角色
藏青 #0D3D9F 9.61:1 AAA 9.61:1 结构色 —— 正文、标题、深色区块、主按钮
玫红 #F7226F 3.88:1 AA·大字 → 大字 AA 3.88:1 强调色 —— 行动按钮、大字、跳色、标签
青蓝 #0DAACD 2.75:1 不达标 2.75:1 装饰色 —— 图标、徽章、图形元素
浅粉 #F88EC6 2.17:1 不达标 2.17:1 装饰色 —— 底色衬、深底上的点缀

这张表解释了一个常被误解的现象:角色不是设计者决定的,是数值算出来的。

  • 藏青 9.61:1,远过 7:1 的 AAA 线 —— 所以它可以承担正文,进而可以承担结构。
  • 玫红 3.88:1,差一点够不到 4.5:1 的 AA 正文线 —— 所以它不能做正文,只能用于 ≥18.66px 粗体的大字与实心按钮。这不是保守,是可用性红线。
  • 青蓝 2.75:1、浅粉 2.17:1 完全不具备承载语义的能力 —— 只能退到装饰层。

反过来说:如果一定要让玫红承担正文,就必须把它的明度压到 33.7% 附近(即色阶 700 档),但那会让它变成一种暗红,失去作为强调色所需的视觉音量。这是一次此消彼长,本系统选择保留它的音量,因此把它限制在大字与按钮。

2.6 对比度矩阵

以下是四个品牌色与关键中性色两两之间的实测对比度。深蓝数字=≥4.5:1 可用于正文;玫红数字=3–4.5:1 仅限大字;灰字=<3:1 禁止承载文字。

前景 ↓ / 背景 → 藏青 玫红 青蓝 浅粉 近黑 中灰 浅灰 白
藏青 1.00 2.48 3.50 4.43 1.90 1.67 7.90 9.61
玫红 2.48 1.00 1.41 1.79 4.71 1.49 3.19 3.88
青蓝 3.50 1.41 1.00 1.27 6.66 2.10 2.26 2.75
浅粉 4.43 1.79 1.27 1.00 8.42 2.66 1.78 2.17
近黑 1.90 4.71 6.66 8.42 1.00 3.17 15.02 18.28
中灰 1.67 1.49 2.10 2.66 3.17 1.00 4.74 5.77
浅灰 7.90 3.19 2.26 1.78 15.02 4.74 1.00 1.22
白 9.61 3.88 2.75 2.17 18.28 5.77 1.22 1.00

读法:行是前景,列是背景。例如「玫红 × 藏青」= 2.48:1,说明玫红文字压在藏青底上不达标;反过来「藏青 × 玫红」= 2.48:1,同样不达标。藏青与玫红不能互为文字与底色 —— 这是本系统一条硬性配对禁令。

03 色阶推演

上面四个品牌色只是「一个点」。要支撑整个界面,每个品牌色都需要扩展成一条色阶 —— 一条从近白到近黑的 10 级梯度。本节给出这套色阶的推导公式,公式可直接套用到任意新色。

3.1 三条推演规则

色阶不是「调浅一点、调深一点」试出来的。它由三条明确规则生成,因此结果可复现、可审计。

规则一 · 色相锁定 整条色阶 色相 H 恒定不变。取色阶上的任何一档,色相角都等于基准色相的原始值。这是「同一条色阶」之所以成立的唯一依据。

规则二 · 明度插值 以基准色所锚定的档位为支点,向亮端(L=97%)与暗端(L=12%)两个方向线性插值。支点档位的色值精确等于原始品牌色。

规则三 · 饱和补偿 从支点向亮端,饱和度线性衰减至基准的 62%;向暗端衰减至 88%。这一步不可省 —— 明度大幅变化时饱和度必须同步补偿,否则亮端会发灰、暗端会发黑。

为什么亮端要「降饱和」 这不是审美调整,是补偿。在 HSL 空间里把明度推到 97% 而保持饱和度不变,颜色会逼近纯色而不是逼近白色,视觉上会显得刺眼;反过来让饱和度同步下降,得到的才是真正像「被光稀释过的同色」。暗端同理:明度压到 12% 而饱和度不降,会糊成一种发黑的浊色。

3.2 推导算法

伪代码 · 色阶生成

// 输入:基准色 (H, S, L) 与其锚定档位 k
// 输出:10 档色阶 L[0..9] ∈ {50,100,200,...,900}

for i in 0..9:
  if i <= k:                    // 亮端
    t = (i - k) / (0 - k)
    L = L_base + (97.0 - L_base) * t
    S = S_base * (1 - (1 - 0.62) * t)
  else:                          // 暗端
    t = (i - k) / (9 - k)
    L = L_base + (13.0 - L_base) * t
    S = S_base * (1 - (1 - 0.88) * t)
  hex[i] = HSL_to_HEX(H, S, L)   // H 恒定,从不修改

把四个品牌色代入这套算法,得到的支点档位分别是 700 / 600 / 500 / 200,与 §2.4 的锚定表一致。这也是为什么浅粉的色阶几乎是从「已提亮」的位置向两端展开 —— 它本身就坐在阶梯的亮区。

3.3 四条色阶

  • 藏青:锚点 700 · 色相锁定 220.3° · 基准饱和度 84.9%
  • 玫红:锚点 500 · 色相锁定 338.3° · 基准饱和度 93.0%
  • 青蓝:锚点 600 · 色相锁定 190.9° · 基准饱和度 88.1%
  • 浅粉:锚点 200 · 色相锁定 328.3° · 基准饱和度 88.3%

3.4 各色阶明细与可用性

「压白底」为该色作为文字压在白底上的对比度;「白色压它」为白色文字压在该色上的对比度;「白底等级」以「压白底」判定。

藏青 · 基准 #0D3D9F(档位 700)

档位 色值 饱和度 明度 压白底 白色压它 白底等级 标记
50 #F3F6FB 52.6% 97.0% 1.08:1 1.08:1 不达标 —
100 #CFDAF2 57.2% 88.0% 1.4:1 1.4:1 不达标 —
200 #A8BEEA 61.9% 78.9% 1.87:1 1.87:1 不达标 —
300 #7FA1E5 66.5% 69.9% 2.58:1 2.58:1 不达标 —
400 #5483E2 71.1% 60.8% 3.67:1 3.67:1 AA·大字 —
500 #2764E1 75.7% 51.8% 5.25:1 5.25:1 AA —
600 #154FC5 80.3% 42.7% 7.1:1 7.1:1 AAA —
700 #0D3D9F 84.9% 33.7% 9.61:1 9.61:1 AAA 锚点
800 #0C2B6B 79.8% 23.4% 13.35:1 13.35:1 AAA —
900 #08193A 74.7% 13.0% 17.35:1 17.35:1 AAA —

玫红 · 基准 #F7226F(档位 500)

档位 色值 饱和度 明度 压白底 白色压它 白底等级 标记
50 #FCF3F6 57.7% 97.0% 1.09:1 1.09:1 不达标 —
100 #F5CFDD 64.7% 88.6% 1.41:1 1.41:1 不达标 —
200 #F1A8C3 71.8% 80.2% 1.89:1 1.89:1 不达标 —
300 #F07FA8 78.9% 71.9% 2.53:1 2.53:1 不达标 —
400 #F2528C 85.9% 63.5% 3.3:1 3.3:1 AA·大字 —
500 #F7226F 93.0% 55.1% 3.88:1 3.88:1 AA·大字 锚点
600 #D80B55 90.2% 44.6% 5.12:1 5.12:1 AA —
700 #A30B42 87.4% 34.0% 7.82:1 7.82:1 AAA —
800 #6F092E 84.6% 23.5% 11.97:1 11.97:1 AAA —
900 #3C061A 81.8% 13.0% 17.03:1 17.03:1 AAA —

青蓝 · 基准 #0DAACD(档位 600)

档位 色值 饱和度 明度 压白底 白色压它 白底等级 标记
50 #F3FAFC 54.6% 97.0% 1.06:1 1.06:1 不达标 —
100 #CEECF3 60.2% 88.0% 1.24:1 1.24:1 不达标 —
200 #A6E0ED 65.8% 78.9% 1.45:1 1.45:1 不达标 —
300 #7BD5E9 71.4% 69.8% 1.68:1 1.68:1 不达标 —
400 #4ECCE8 76.9% 60.8% 1.89:1 1.89:1 不达标 —
500 #1EC5E9 82.5% 51.8% 2.06:1 2.06:1 不达标 —
600 #0DAACD 88.1% 42.7% 2.75:1 2.75:1 不达标 锚点
700 #0D819A 84.6% 32.8% 4.54:1 4.54:1 AA —
800 #0B596A 81.1% 22.9% 7.92:1 7.92:1 AAA —
900 #07323B 77.5% 13.0% 13.74:1 13.74:1 AAA —

浅粉 · 基准 #F88EC6(档位 200)

档位 色值 饱和度 明度 压白底 白色压它 白底等级 标记
50 #FCF3F8 54.7% 97.0% 1.09:1 1.09:1 不达标 —
100 #F5C5DF 71.5% 86.8% 1.51:1 1.51:1 不达标 —
200 #F88EC6 88.3% 76.5% 2.17:1 2.17:1 不达标 锚点
300 #F464B0 86.8% 67.4% 2.88:1 2.88:1 不达标 —
400 #EF3A9A 85.3% 58.4% 3.66:1 3.66:1 AA·大字 —
500 #E71484 83.8% 49.3% 4.35:1 4.35:1 AA·大字 —
600 #BB126B 82.2% 40.2% 6.16:1 6.16:1 AA —
700 #900F53 80.7% 31.1% 8.83:1 8.83:1 AAA —
800 #650C3B 79.2% 22.1% 12.58:1 12.58:1 AAA —
900 #3B0723 77.7% 13.0% 16.93:1 16.93:1 AAA —

从色阶取色的规则 先确定需要的对比度,再到色阶上找对应档位,而不是先挑一个好看的颜色再想办法让它可读。要正文就取 ≤ 600 档的深端,要大字就取 500–700 档,要底色就取 50–200 档,要装饰就取 300–400 档。档位与用途是一一对应的。

关于 800 / 900 两档 这两档在常规界面里使用频率很低,但它们不是冗余。它们的用途是深色模式底色与大面积深色区块 —— 用 700 档(即品牌色本身)铺满整屏会显得过饱和,800/900 档则是它压制后的版本,同色相、更低明度、更低饱和,适合作为整片背景。这是深色模式能在不引入任何新色相的前提下成立的原因。

04 中性色阶

四个品牌色只解决「强调」,不解决「结构」。级别、分隔、底层、正文、边框(的概念)、禁用态 —— 这些占界面面积 90% 以上的角色,全部由一条中性色阶承担。本节定义这条色阶,以及隔几级才看得出来这个实操问题。

4.1 十二级冷调灰阶

色阶共 12 级,从纯白 N0 到近黑 N11。两条设计决定:

  • 数量取 12 而非 10。层级表达需要足够细的颗粒度,尤其在浅端 —— 表层层级之间的差距必须小而连续,级数太少会导致「要么看不出,要么太跳」。
  • 带蓝色倾向(H=222)。品牌主色藏青的色相是 220.3°,灰阶取 222° 与之基本一致,且饱和度极低(最高 35%,最暗端 26%)。结果是每一级灰都带一丝察觉不到的冷调。纯中性灰(S=0)与这组高饱和品牌色放在一起会显得脏,这是常见问题,带倾向的灰可以消除它。

4.2 各级用途分配

令牌 色值 明度 压白底 压近黑 白底等级
N0 #FFFFFF 100.0% 1:1 18.28:1 不达标
N1 #F7F9FB 97.8% 1.06:1 17.32:1 不达标
N2 #F1F3F8 95.8% 1.11:1 16.47:1 不达标
N3 #E5E9F1 92.2% 1.22:1 15.02:1 不达标
N4 #D9DEEA 88.5% 1.35:1 13.57:1 不达标
N5 #C7CEDE 82.5% 1.58:1 11.59:1 不达标
N6 #A3ADC4 70.5% 2.25:1 8.12:1 不达标
N7 #7F89A1 56.5% 3.5:1 5.22:1 AA·大字
N8 #5D6679 42.0% 5.77:1 3.17:1 AA
N9 #414858 30.0% 9.16:1 2:1 AAA
N10 #2B3140 21.0% 12.99:1 1.41:1 AAA
N11 #11151D 9.0% 18.28:1 1:1 AAA
令牌 色值 系统用途 禁止用途
N0 #FFFFFF 页面底色、卡片底、深色块上的文字 —
N1 #F7F9FB 极轻微的表层浮动(悬停态) 正文底色(与白几乎不可分)
N2 #F1F3F8 分区底色、侧栏底、说明块底 —
N3 #E5E9F1 次级底块、表格隔行、禁用底 —
N4 · N5 #D9DEEA · #C7CEDE 分隔块、占位图形、禁用控件底 承载文字
N6 #A3ADC4 占位图形、装饰条、图标底 承载文字
N7 #7F89A1 辅助文字(≥18.66px 粗体) 小字正文
N8 #5D6679 正文与次要文字(默认) —
N9 #414858 正文强调、小字正文 —
N10 #2B3140 标题、深色底块 —
N11 #11151D 深色区块底、页脚、代码块底、主标题 —

一处需要留意 N8(#5D6679,压白底 5.77:1)与 N9(#414858,9.16:1)都达标,区别在用途而不在达标与否:N8 是默认正文,N9 是正文中需要「更重一点」的部分。两者同时出现时差距才可读,单独使用无法察觉差别。

4.3 层级差:隔几级才看得出来

这是实操中最常踩的一个坑。相邻两级看起来「几乎一样」,隔一级仍然不够,隔两级才刚够分辨。以下是以浅端底色为基准的实测对比度:

间隔 典型对比度 视觉判断 建议用法
相邻 1 级 1.05 – 1.18 : 1 几乎不可辨,需要并排对比才能察觉 仅用于悬停态等极微妙反馈
隔 2 级 1.11 – 1.31 : 1 可辨,边界清楚但不抢戏 表层层级默认值(卡片浮起 / 下沉)
隔 3 级 1.22 – 1.53 : 1 明确分区,无需任何辅助元素 区块级分区、侧栏与主区
隔 4 级以上 1.35 – 2.18 : 1 强对比,接近「另一个界面」 深色区块、页脚、强调区

结论直接可用:表层层级用隔 2 级,区块分区用隔 3 级。这两个数字替代了原本由描边和阴影承担的层级表达。

为什么不能只隔 1 级 因为屏幕不是纸。在低色域、低亮度、有环境光的实际使用条件下,1.05:1 的差距会被完全抹掉;而对视觉正常的人来说它本就在可辨阈值的边缘。设计评审时在好显示器上看是「能看出来」的,到用户手里就是「没看出来」。取 2 级是留出安全余量,不是浪费层级。

05 渐变规范

界面及其配套视觉统一使用纯色与明确的色阶,不使用渐变。层级通过明度差和色块拼接表达;强调或状态变化应从既定令牌中选择单一档位。

  • 禁止线性、径向、锥形以及由品牌色过渡到透明的渐变。
  • 渐变背景上的文字对比度会随位置变化,难以稳定验证;文字与背景应使用确定的颜色值。
  • 需要表现色彩层次时,使用色阶中的实色或离散的纯色色块,不使用连续过渡。

06 设计令牌

令牌是这套系统的最小单位。原则很简单:凡是会被重复使用、且需要保持一致的值,都必须有一个名字。令牌表之外不允许存在任何自由值。

6.1 命名规范

  • --c-{role} —— 品牌色。用角色命名而非色相名(--c-struct 而不是 --c-navy)。理由:若哪天品牌换成绿色,「结构色」这个名字依然成立,而「藏青」会变成一个说谎的名字。
  • --n{0-11} —— 中性色阶。数字即明度序位,越小越浅。
  • --r-size / --sp1…--sp9 / --fs-size —— 尺寸类令牌,序号或语义名均可,但同一类必须统一。
  • --line-subtle —— 唯一允许的细线令牌,仅用于相邻两面没有可用明度差且仍需标明边界的情况。
  • --c-role 与 --n0…--n11 之外的语义色一律不新增。需要「成功 / 警告 / 危险」时,从现有色阶取档,不引入新色相(见 §11.4)。

6.2 完整令牌表

CSS 自定义属性 · 全量令牌

/* ——— 品牌色 · 4 ——— */
--c-struct: #0D3D9F;   /* 结构色 · 藏青 */
--c-accent: #F7226F;   /* 强调色 · 玫红 */
--c-deco-1: #0DAACD;   /* 装饰色 · 青蓝 */
--c-deco-2: #F88EC6;   /* 装饰色 · 浅粉 */

/* ——— 中性色阶 · 12 ——— */
--n0: #FFFFFF;
--n1: #F7F9FB;
--n2: #F1F3F8;
--n3: #E5E9F1;
--n4: #D9DEEA;
--n5: #C7CEDE;
--n6: #A3ADC4;
--n7: #7F89A1;
--n8: #5D6679;
--n9: #414858;
--n10: #2B3140;
--n11: #11151D;

/* ——— 同明度边界补充线 · 唯一形态 ——— */
--line-subtle: 1px solid var(--n4);

/* ——— 圆角 · 5 档 ——— */
--r-sm: 8px; --r-md: 12px; --r-lg: 20px;
--r-pill: 999px; --r-full: 50%;

/* ——— 间距 · 9 档 ——— */
--sp1: 4px; --sp2: 8px; --sp3: 12px; --sp4: 16px;
--sp5: 24px; --sp6: 32px; --sp7: 48px; --sp8: 64px; --sp9: 96px;

/* ——— 字号 · 8 档 / 行高 · 4 档 ——— */
--fs-xs: 12px; --fs-sm: 13px; --fs-base: 15px; --fs-md: 17px;
--fs-lg: 22px; --fs-xl: 30px; --fs-2xl: 44px; --fs-3xl: 64px;
--lh-tight: 1.2; --lh-snug: 1.45; --lh-base: 1.7; --lh-loose: 1.85;

/* ——— 字重 · 4 档 ——— */
--w-reg: 400; --w-med: 500; --w-bold: 700; --w-black: 900;

/* ——— 动效 · 3 档 ——— */
--dur-fast: 120ms; --dur-base: 200ms; --dur-slow: 320ms;
--ease: cubic-bezier(.2,.7,.3,1);

/* ——— 层级 · 5 档 ——— */
--z-base: 0; --z-sticky: 100; --z-dropdown: 300;
--z-modal: 600; --z-toast: 900;

6.3 圆角:五档封顶

圆角是最容易被「顺手写个值」破坏的一项。本系统圆角只有五档,没有 border-radius: 10px 这样的写法,圆角为 0 时不声明该属性(默认值即 0),因此也不占用档位。

  • --r-sm 8px
  • --r-md 12px
  • --r-lg 20px
  • --r-pill 999px
  • --r-full 50%
令牌 值 适用元素
--r-sm 8px 标签内块、小按钮、单选块、代码内联块
--r-md 12px 输入框、次级卡片、色块、分页项
--r-lg 20px 主卡片、区块容器、弹层、图片容器
--r-pill 999px 主按钮、标签、徽章、输入胶囊
--r-full 50% 头像、圆点标记、圆形徽章
(默认) 0 页面区块、整屏容器、深色区块 —— 不声明

一条容易忽略的规则 嵌套时的圆角必须外大内小:外层容器用 --r-lg,内部元素最多用到 --r-md。若内外同值,内层圆角在视觉上会显得比外层更圆,破坏规整感。这是几何问题,不是审美问题。

6.4 间距:九档等比

间距从 4px 起,按约 1.5 倍递增。所有 padding / margin / gap 只能取这九档。

  • --sp1 — 4px
  • --sp2 — 8px
  • --sp3 — 12px
  • --sp4 — 16px
  • --sp5 — 24px
  • --sp6 — 32px
  • --sp7 — 48px
  • --sp8 — 64px
  • --sp9 — 96px
令牌 值 典型用途
--sp1 4px 图标与文字之间、标签内边距
--sp2 8px 行内元素间距、紧凑列表项间距
--sp3 12px 列表项内边距、表单字段内边距
--sp4 16px 卡片内边距(紧凑)、网格间距(密)
--sp5 24px 卡片内边距(标准)、组件之间
--sp6 32px 卡片内边距(宽松)、区块内元素间距
--sp7 48px 区块之间的间距
--sp8 64px 大区块之间的间距
--sp9 96px 章节级留白、页面上下边距

6.5 字号与行高

  • --fs-3xl 64px / 1.2 — 页面主标题
  • --fs-2xl 44px / 1.2 — 区块大标题
  • --fs-xl 30px / 1.2 — 章节标题
  • --fs-lg 22px / 1.45 — 卡片标题 / 导语
  • --fs-md 17px / 1.7 — 正文强调
  • --fs-base 15px / 1.7 — 默认正文
  • --fs-sm 13px / 1.7 — 辅助文字
  • --fs-xs 12px / 1.7 — 标注 · 元信息

行高与字号成反比:字号越大行高越紧(64px 配 1.2),字号越小行高越松(13px 配 1.7)。原因是文字越大,行间的视觉空隙本身就越大,再配大行高会散架;文字越小越需要额外的行间距来保证横向阅读不串行。上表中各条已按此规则配对,直接取用即可。

6.6 字重与动效

字重 · 四档 400 正文 · 500 次级强调 · 700 小标题与按钮 · 900 大标题与数字。
中文环境下不使用 100–300 的细体:中文字形笔画密集,细体在小字号下笔画会糊成一片,可读性显著低于西文。

动效 · 三档 120ms 悬停、按下等即时反馈 · 200ms 展开、淡入等常规过渡 · 320ms 弹层、抽屉等大幅位移。
缓动统一使用 cubic-bezier(.2,.7,.3,1)(快出慢停)。禁止为动效添加任何形式的不透明度变化,需要弱化时用色阶换色。

令牌化的验收标准 把样式文件里所有的字面色值、尺寸数字搜一遍 —— 如果出现任何不属于令牌表的值,令牌化就没有完成。这项检查应该在每次提交前自动执行,而不是靠人眼复查。

07 层级表达

本节规定如何用明度差、色块和留白表达层级。边界细线仅按下文的同明度例外使用,不表达层级或状态。

7.1 三种手段与优先级

优先级 手段 承担范围 数值依据
1 底色切换 区块级分区、页面段落划分 相邻区块隔 3 级(≈1.3:1)
2 色块嵌套 同类元素内的层级、卡片与底的关系 卡片与底隔 2 级(≈1.2:1)
3 尺寸与留白 紧密相邻的模块边界、分组 间距差 ≥ 2 档(如 24px vs 48px)

优先级的意义在于用最上面的手段解决问题。能用底色切换解决的,就不要动用色块嵌套 —— 每往下一层,页面的视觉复杂度就上升一级。相邻面无法采用明度差区分、且确实需要边界时,才使用 --line-subtle;它不用于层级或状态。

7.2 核心推论:浮起与下沉

两条方向相反的规则 浅灰底上放白块 → 白块比底亮,读作「浮起」。
白底上放浅灰块 → 灰块比底暗,读作「下沉」。
相邻区块应反向交替:白 → 灰 → 白 → 灰。全程同向会导致层级链条断裂,读者无法判断哪一层更靠前。

  • N3 底 · 隔 2 级
  • N0 卡片 · 比底更亮 → 浮起
  • N3 底 · 隔 2 级
  • N0 底 · 基准
  • N2 卡片 · 比底更暗 → 下沉
  • N0 底 · 基准

上图两行分别为「白卡浮在灰底上」与「灰卡沉在白底上」。两者的层级关系在视觉上同样清晰,但方向相反 —— 不要在同一页里混用两种方向表达同一层级。

7.3 五个常见场景的对照做法

场景 无描边 / 无阴影的做法 关键数值
卡片 底 N2,卡片 N0;悬停时卡片转 N1 差 2 级 · 悬停差 1 级
导航栏 不做毛玻璃、不加下边线。栏底用 N0,与内容区之间以 64px 留白区隔 留白 ≥ --sp8
弹层 / 对话框 用 N0 大圆角块压在 N3 遮色底上。遮色底用实色而非半透明 —— 需要遮住内容时,用能完整覆盖的实色 --r-lg + --z-modal
表头 表头行用 N11 深底 + 白色文字;数据行白 / N1 交替。利用深色表头本身形成分界,无需分割线 行间隔 1 级
分组 / 分隔 用「间距差」表达:组内元素间距 --sp2,组间 --sp6 间距差 4 档
选中态 底色整体切换 + 文字色同步切换,不使用边框变化 对比度 ≥ 4.5:1

最常见的三个破坏动作 **一、**当卡片与页面底色已有明度差时仍加描边 —— 这会重复表达边界,使版式变碎;只有相邻面无可用明度差且仍需标界时,才使用 --line-subtle。**二、**为了「跟背景分开」给导航栏加毛玻璃 —— 模糊是一种深度伪造,属于透明度家族的补偿手法,与扁平化冲突。**三、**用 box-shadow 做卡片浮起 —— 阴影的本质是模拟光照下的深度,本系统不承认这个隐喻,改用色阶明度差。

正确 · 底色分层 卡片标题 卡片以底色浮起,边界由明度差自然形成。 错误 · 描边分层 卡片标题 描边与底色同时表达层级,信息重复且版面变碎。 右侧反例在已有明度差时仍加描边;本系统的细线例外只用于相邻面无可用明度差的边界。

08 组件规范

本节给出核心组件的规范。每个组件只使用令牌表中的值;常规状态和键盘焦点都通过底色与文字色表达。边界细线仅按 §10 的同明度例外使用,不叠加阴影或透明度。

按钮

  • 主要行动 / 次要行动 / 安静按钮 / 已禁用
  • 小号 / 默认 / 大号
层级 底色 文字 悬停 使用约束
主要行动 --c-accent --n0 --n10 每屏最多 1 个
次要行动 --c-struct --n0 --n11 同组内不超过 1 个
安静按钮 --n0 --n10 --n3 用于「取消 / 返回」等非决策操作
禁用 --n4 --n7 不变 用底色表达禁用,不降低透明度

为什么禁用态不用透明度 把按钮设成 opacity: .4 是最省事的做法,但它带来两个问题:一是文字对比度同样被削弱,禁用态文字往往掉到 2:1 以下,视力不佳的用户完全看不见;二是引入了透明度这个维度,与系统禁则冲突。正确做法是用 --n4 底 + --n7 文字,对比度约 2.6:1,正好处在「可辨认但明显不活跃」的区间。

输入框

  • 默认态 · 占位文字 N7 / 聚焦态 · :focus-visible 焦点指示(见 §09.2) / 错误态 · 文字转强调色
  • 默认态:N0 底,占位文字 N7。不要给输入框加描边 —— 它的边界由与页面底色的明度差确立;若页面本身是白色,则输入框改用 N2 底。
  • 聚焦态:使用 :focus-visible 切换为焦点色块(见 §09.2),不加描边。
  • 错误态:不用红色底,将文字与下方提示改为强调色玫红,并保持 --w-med 字重。错误信息必须同时有文字说明,不能只靠颜色。

标签与徽章

  • 结构标签 / 中性标签 / 强调标签 / 深色标签
  • 进行中 / 待处理 / 已归档 标签统一使用 --r-pill 圆角。**状态区分优先用「圆点 + 文字」而非「整块变色」**因为色盲用户无法分辨纯色块的差异,而圆点位置与文字是无障碍的。

卡片

  • 分类标签 / 卡片标题写在两行以内的位置 / 正文使用 N8,行高 1.45。卡片底色 N0,悬停转 N1 —— 变化只有一级,足以提示可交互,但不造成闪烁感。 / 元信息 · N7 / 变体 / 灰底卡片(下沉式) / 当页面底色为白时,卡片改用 N2 底。用于信息密集的列表页,视觉重量比白卡更轻。 / 元信息 · N7 两处卡片的元信息与正文对比度:正文 N8 = 5.77:1(达标),元信息 N7 = 3.5:1(仅限 ≥18.66px 粗体,若尺寸更小须换用 N8)。

分页

  • ‹ / 1 / 2 / 3 / › 选中项用强调色实心(--r-md 圆角,非胶囊),其余用 N0 底、悬停转 N3。不使用边框表达选中 —— 选中是一个状态,用填充表达比用轮廓表达更明确。

组件层的一条通则 悬停、选中、禁用、错误和键盘焦点都通过底色与文字色表达;焦点态使用 §09.2 的单一色块方案,不叠加描边、阴影或透明度。

09 可访问性

可访问性不是附加项,它是本系统中唯一可以推翻其他规则的约束。当视觉规则与可用性冲突时,可用性优先。

9.1 对比度门槛

WCAG 等级 门槛 本系统中可用该级别的颜色
AAA · 正文 ≥ 7:1 藏青(9.61:1)、N9(9.16:1)、N10(12.99:1)、N11(18.28:1)、色阶 600–900 档
AA · 正文 ≥ 4.5:1 N8(5.77:1)、藏青色阶 500–900 档、玫红 800 档、青蓝 800 档
AA · 大字 ≥ 3:1 玫红(3.88:1)、N7(3.5:1)、各色阶 400–500 档
不达标 < 3:1 青蓝(2.75:1)、浅粉(2.17:1)、N0–N6 —— 禁止承载文字

「大字」定义为 ≥ 24px 常规字重,或 ≥ 18.66px 粗体。低于此尺寸一律按正文门槛 4.5:1 判定。

两个高频违规 **一、**把 N7(3.5:1)用作 13px 的辅助文字。这个对比度只够大字,13px 下不达标。辅助文字请用 N8。
**二、**白字压玫红做按钮文案。3.88:1 处于大字线,若按钮文字小于 18.66px 粗体则违规。做法是把按钮文字改为 --w-bold 且尺寸 ≥ 18.66px,或把按钮底色换成藏青。

9.2 键盘焦点:用色块保持可见

键盘操作必须始终有可见焦点提示。WCAG 2.1 成功准则 2.4.7要求键盘可操作界面存在焦点可见的操作模式;焦点状态色块还应符合1.4.11 非文本对比度,与相邻颜色至少达到 3:1。

  • 仅对 :focus-visible 切换焦点色块,并同步调整文字色;不使用 outline、边框、阴影或透明度。
  • 相邻底色为 N0–N6 时,使用 --c-struct 底色与 --n0 文字;相邻底色为 N7–N11 时,使用 --n0 底色与 --n11 文字。两组焦点色块均与相邻底色达到至少 3:1,文字对比度也达标。
  • 相邻面使用品牌色时,从现有令牌中选取与相邻颜色对比度达到 3:1 的焦点底色,并选择满足文本对比度要求的文字色。
  • 不得移除键盘焦点指示;焦点仅通过色块和文字色表达,不叠加描边。

9.3 色盲与色彩依赖

本系统的核心色彩分工对色盲相对友好,原因在于角色由明度而非色相区分:藏青(L=33.7%)与玫红(L=55.1%)的明度差达 21.4 个百分点,即使在完全无色觉的情况下,两者仍可被区分。

但仍然必须遵守三条:

  • **不用颜色单独承载信息。**错误态不能只靠变红,必须同时有文字说明或图标。
  • **状态区分优先使用形状与位置。**圆点、序号、图标位置在无色觉时仍然有效。
  • **若未来扩展辅助色(见 §11.4),必须通过色盲安全校验。**新增色相应分别模拟红色盲、绿色盲、蓝色盲三种情况下的可区分性。

9.4 其他硬性要求

项目 要求
点击目标 可交互元素最小 44×44px,间距 ≥ 8px
正文宽度 单行 40–75 字符(中文约 25–40 字),超出须分栏
正文字号 不小于 15px;移动端不小于 15px
动效 提供 prefers-reduced-motion 降级;不出现 3 次/秒以上的闪烁
语义结构 标题层级连续;表格使用真实 table 元素并标注表头
语言标注 页面声明 lang;中英混排时英文片段单独标注

10 禁用清单

以下十条为界面硬性约束。相邻面没有可用明度差且仍需边界时,描边仅按本节规定使用;其余禁则不得违反。建议第 §12 的检查清单与此处逐条对应。

  • 禁止任何形式的渐变;界面及配套视觉不得出现线性、径向、锥形或透明度渐变。层级由色阶明度差和纯色色块承担(§05)。
  • 描边仅作同明度边界补充;只有相邻两面没有可用明度差、且仍需要标明边界时,允许使用 --line-subtle。描边不用于层级、选中或焦点;键盘焦点使用 §09.2 的色块状态。
  • 禁止阴影;不得使用 box-shadow、text-shadow、filter: drop-shadow。阴影是深度伪造,与扁平化冲突。
  • 禁止透明度;不得使用 rgba()、hsla()、opacity < 1、backdrop-filter。需要弱化时改用色阶上的更浅档位。
  • 禁止自由圆角值;圆角只能取五档令牌,其余值一律不允许。圆角为 0 时不声明属性。
  • 禁止自由尺寸值;间距、字号只能取令牌。出现 13px 字号、10px 圆角、18px 间距即视为违规。
  • 禁止引入第五个色相;品牌外色相一律不得进入界面。需要语义色(成功 / 警告 / 危险)时,从现有色阶取档(§11.4)。
  • 禁止藏青与玫红互为文字与底色;两者互压对比度为 2.48:1 与 2.48:1,均不达标。
  • 禁止用颜色单独承载信息;错误、状态、分类必须同时有文字、图标或位置差异。
  • 禁止文字压在渐变上;渐变上的对比度是区间而非确定值,可访问性无法保证。

自查方式 十条中有六条可以自动检测。建议在提交前执行一次字符串扫描:搜索 gradient、box-shadow、rgba(、opacity 和 border;仅当边界满足同明度条件时,才允许使用 --line-subtle。同时检查是否存在令牌表外的 px 值。这项检查应当成为流程的一部分,而不是依赖人工复查 —— 能被自动检测的规范,才有资格被称为规范。

11 跨项目复用

本节回答最初那个问题:这套配色逻辑能不能套用到其他项目上。结论是能,但必须补上三个约束 —— 否则会退化成一堆看起来还行、放在一起却散架的颜色。

11.1 五步配方

步骤 动作 硬性约束 校验方法
1 定 1–2 个主题色 明度压到 30%–40%,饱和度过 80% 算压白底对比度,需 ≥ 7:1
2 为每个主题色派生浅色辅助色 同色相提亮 或 邻近色偏移 ≤ 30° 必须能回答「它从哪个色派生」
3 把四个色的饱和度收进窄区间 极差 ≤ 10 个百分点 列表比对饱和度数值
4 把明度错开到不同档位 四个色落在 四个不重叠的明度带 映射到 10 级阶梯,看档位是否重复
5 补一条中性色阶 10–12 级,带 3–5% 的品牌色相倾向 检查最浅端相邻两级是否可辨(≥1.05:1)

11.2 关键约束:辅助色必须有出处

本系统最重要的一条复用规则 辅助色不能独立选择,它必须从某个主题色派生而来。

本例中:青蓝之于藏青是邻近色偏移(+-29.4°,同一族);浅粉之于玫红是同族提亮(色相差仅 10.0°,明度 +21.4 个百分点)。两者都有明确的出处。

反之,若插入一个无关的浅黄或浅绿,即使它的对比度完全合格、明度也错开了,视觉上仍会立刻散掉 —— 因为它没有出处。这是「配色是否成套」的分水岭。

11.3 三种常见错法

错误一 · 四色同明度 四个色的明度都落在 45%–60% 区间。结果:四个色争夺同一角色,只能靠加大面积来区分,页面必然花。修复方式是按 §11.1 步骤 4 把明度错开。

错误二 · 饱和度不齐 三个色在 85% 以上,一个色在 45% 附近。结果:那个低饱和色会被读成「没调好」。若要整体柔和,必须四个一起降,保持极差 ≤ 10 个百分点。

错误三 · 辅助色另起炉灶 主题色是蓝,辅助色却选了一个与蓝毫无关系的浅绿或浅黄。结果:两套语言互不相认。修复方式是回到 §11.2,让辅助色从主题色派生。

错误四 · 跳过对比度直接分配角色 凭「这个色好看」决定它做标题。结果:上线后才发现该色压白底只有 2.5:1,无法承载文字,只能临时调整字号或加粗,破坏版面。修复方式是先算对比度,再决定角色。

11.4 语义色(成功 / 警告 / 危险)怎么办

这是一个绕不开的问题:本系统禁止引入第五个色相,但产品通常需要红、黄、绿三态。

处理原则:语义色从现有色阶取档,而不新增色相。

语义 本系统处理 依据
危险 / 错误 使用强调色玫红及其色阶 700–900 档 玫红在这个系统里本身承担「需要注意」的角色,语义一致
成功 / 完成 使用结构色藏青及其色阶 500–700 档 以品牌主色表达正向状态,避免引入绿色
警告 / 待处理 使用装饰色青蓝及其色阶 600–800 档 青蓝处于色环的「冷偏中」位置,可作为中性提醒
中性 / 归档 使用中性色 N7–N8 —

这条规则的适用边界 该做法适合品牌调性统一、信息密度中等的产品(内容站、SaaS、品牌页)。不适用于金融、医疗、工业控制等强语义行业 —— 那些场景下「红必须代表涨或危险、绿必须代表跌或安全」是不可让步的行业惯例与安全要求,此时应当保留标准语义色相,并把品牌色退到装饰层。规范的价值在于被遵守,而规范的前提是承认例外。

11.5 换色时的改动清单

若要把这套系统迁移到另一个品牌色,需要改动的只有以下几处,其余全部自动继承:

  1. 四个品牌色令牌值(--c-struct / --c-accent / --c-deco-1 / --c-deco-2)
  2. 中性色阶的色相倾角(把 H=222 换成新主色的色相)
  3. 用 §03 的算法重跑四条色阶
  4. 复核对比度表,确认步骤 1 的四个色仍满足原有角色分配

圆角、间距、字号、字重、动效、层级、组件规范全部不需要改动 —— 这正是把「视觉手段」与「系统规范」分开的价值:换肤不动骨架。

12 交付检查清单

共 31 项,覆盖色彩、令牌、层级、扁平化、可访问性、交付六个维度。建议逐条勾选,未通过项不得交付。

色彩

  • 页面中只出现 4 个品牌色相 + 1 条中性色阶,无第五色相
  • 四个品牌色的饱和度极差 ≤ 10 个百分点
  • 四个品牌色的明度落在互不重叠的档位
  • 所有文字对比度达标:正文 ≥ 4.5:1,大字 ≥ 3:1
  • 未出现「藏青文字压玫红底」或反向的配对
  • 颜色未单独承载信息(有文字 / 图标 / 位置辅助)

令牌

  • 样式文件中无字面色值,全部引用令牌
  • 圆角只取五档,无自由值
  • 间距、字号只取令牌表内的值
  • 嵌套元素圆角外大内小
  • 增删一个主题色时,只改令牌定义即可全局生效

层级

  • 无任何 box-shadow / text-shadow / drop-shadow
  • 描边只在相邻面无可用明度差且仍需标界时使用 --line-subtle;不用于层级、选中或焦点
  • 相邻区块明度差 ≥ 2 级(表层)/ ≥ 3 级(区块)
  • 页面区块底色方向反向交替,未全程同向
  • 弹层使用实色遮色底,未使用半透明

扁平化

  • 无 rgba() / hsla()
  • 无 opacity < 1 的装饰性用法
  • 无 backdrop-filter
  • 禁用态用色阶表达,未使用透明度
  • 无任何形式的界面层渐变

可访问性

  • 键盘可完整遍历页面,焦点始终可见
  • 键盘焦点使用 §09.2 的色块指示,未被隐藏
  • 可点击目标 ≥ 44×44px
  • 正文宽度在 25–40 中文字符之间
  • 提供了 prefers-reduced-motion 降级

交付

  • 已附完整令牌表与色阶明细
  • 色阶由公式生成,可复现,非手工微调
  • 已附对比度矩阵与达标标注
  • 已说明语义色的处理方式与适用边界
  • 新色接入流程已在文档中写明

最后一条 这份文档的终点不是「这套视觉好不好看」,而是「这套规则能不能被下一个执行者直接使用」。

因此交付时请附上令牌表、色阶明细与对比度矩阵 —— 让接受方不必再问任何一个「这里该用什么值」的问题。可复用的规则,比漂亮的页面更值得被交付。