Ant Design DESIGN.md 深度解析:v6 默认浅色主题的设计令牌体系与落地实现
【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/GitHub_Trending/an/ant-design
DESIGN.md 是 Ant Design 仓库根目录下的一份面向 AI 设计工具与人类开发者的设计语言描述文件:它用 YAML front-matter 声明了 v6 默认浅色主题的全部视觉令牌(颜色、字体、圆角、间距与 20 余个组件原型),用正文阐述"自然、确定、有意义、增长"四大设计价值观背后的决策逻辑。读完本文,你将掌握 Ant Design 默认主题的令牌全貌、"种子令牌 → 派生算法 → 组件令牌"的三层主题架构,以及通过ConfigProvider.theme完成种子覆盖、算法切换、组件级定制与零运行时 CSS 提取的完整实操路径。
DESIGN.md 是什么:AI 可读的设计语言描述文件
DESIGN.md 描述的正是Ant Design v6 的默认浅色主题(light theme),并采用语义化版本约束自身:主版本(v5 → v6)代表设计语言的整体翻新,而次版本与补丁版本内该文档保持稳定,每次发布内的令牌漂移记录在 CHANGELOG.en-US.md 中。
这份文件是开源设计系统 Ant Group 长期用于交付企业级软件——中后台控制台、仪表盘与运营工具——的视觉规范沉淀。它诞生于 2015 年的产品目标:给大型产品团队一个"共享且有立场"的基础设施,让高密度的数据界面不必在每一块画布上重新决策基础视觉问题。
在仓库中,这份文件与配套文档 design.md 中文指南、主题核心实现 components/theme/ 共同构成"规范—实现—消费"的闭环;仓库也提供了 tests/design-md.test.ts 对其做回归验证。AI 设计工具(如 Figma Make、Stitch 类工具)可以直接读取该文件,按 Ant Design 的视觉语言生成界面;命令行方式可通过@ant-design/cli的antd design.md(支持--format json、--lang zh)获取同一份内容,详见 CLI 文档。
四大设计价值观:每个决策的裁决标准
系统由四个价值观统领,它们不仅是口号,而是冲突时的裁决规则:
- Natural(自然):界面遵循既有约定,不让回访用户感到意外。操作系统与上一代企业软件中已经存在的模式优先于新发明。
- Certain(确定):用户始终知道当前处于什么状态、自己的输入产生了什么效果、下一步是什么。Hover、focus、loading、error 状态必须显式且一致。
- Meaningful(有意义):视觉强调只保留给"行动"。不传达信息的装饰一律移除。
- Growing(增长):系统能从小表单扩展到高密度表格、多租户管理控制台而不失去一致性。
Do/Don'ts 中的第一条 Do 即呼应此点:两个方案冲突时,那个让用户状态更确定、更易读的方案胜出。
颜色体系:种子色展开、中性文本与预置色边界
种子与派生
调色板由 1 个primary品牌种子色、4 个语义状态种子(success、warning、error、info)以及中性基础色(文本与表面)构成。颜色种子会自动展开为覆盖背景浅染、hover、active、描边等变体的梯度阶梯——改一个种子,整套派生调色板随之移动。这一机制在源码中直接可见:defaultAlgorithm 的派生函数 调用@ant-design/colors的generate()为每个预置色生成 10 级梯度,genColorMapToken.ts 再从中取位映射出语义令牌,例如colorPrimaryBg取主色阶梯第 1 级(即#E6F4FF,对应菜单选中背景)、hover 取第 5 级(#4096FF)、active 取第 7 级(#0958D9)——与 DESIGN.md front-matter 中button-primary-hover: #4096FF、button-primary-active: #0958D9的取值一一对应。
DESIGN.md 声明的完整颜色令牌如下(摘自文件 YAML front-matter):
| 令牌 | 值 | 角色 |
|---|---|---|
primary/info/blue | #1677FF | 品牌主色,动作、链接、聚焦环、选中导航、激活 Tab |
blue-7 | #0958D9 | 主色深一档,用于 active 态与 Tag 文字 |
success/green | #52C41A | 成功状态 |
warning/gold | #FAAD14 | 警告状态 |
error/red | #FF4D4F/#F5222D | 错误状态 |
purple/cyan/magenta/orange/yellow/volcano/geekblue/lime | #722ED1/#13C2C2/#EB2F96/#FA8C16/#FADB14/#FA541C/#2F54EB/#A0D911 | 预置分类色 |
surface | #FFFFFF | 容器表面(bg-container) |
surface-container | #FAFAFA | 表头/浅染容器 |
surface-layout | #F5F5F5 | 页面背景(bg-layout) |
on-surface | #1F1F1F | 主文本 |
on-surface-variant | #595959 | 次要文本 |
on-surface-disabled | #BFBFBF | 占位/禁用 |
outline/outline-variant | #D9D9D9/#F0F0F0 | 描边 |
#1677FF被选为主色,是因为蓝色传达"可信、聚焦",既没有深海军蓝的沉闷企业感,也没有高饱和青色的轻浮感。
中性文本为什么是 rgba 而不是灰度 hex
运行时的令牌系统中,中性文本与覆盖层颜色用rgba(0, 0, 0, α)表达而非扁平灰色 hex。原因是叠加性:文本落在着色卡片或高亮单元格上时,不透明灰色会"切断"底色,而透明黑能自然融合。四个标准 α 阶梯为:
| α | 用途 | 白底合成等价 hex |
|---|---|---|
| 0.88 | 主文本 | #1F1F1F(on-surface) |
| 0.65 | 次要文本 | #595959(on-surface-variant) |
| 0.45 | 三级/说明文本 | — |
| 0.25 | 占位/禁用 | #BFBFBF(on-surface-disabled) |
文档中的 hex 是白底上的合成结果,供需要 hex 的静态导出目标使用;支持 α 的下游消费方应优先使用@ant-design/cssinjs输出的rgba()形式。
可访问性与预置色边界
DESIGN.md 明确记录了可访问性事实:默认视觉令牌中,白字配#1677FF、主文本配浅色选中背景等组合,低于 WCAG AA 对小字号文本的 4.5:1 对比度门槛。若需严格达标,应通过ConfigProvider加深colorPrimary,或使用组件级令牌覆盖,而不是发明一次性颜色。
预置色(blue~lime;运行时时pink是magenta的弃用别名,这一点在 default/index.ts 中以presetPalettes.pink = presetPalettes.magenta向后兼容保留)只保留给标签、图表与分类可视化,绝不用于主 UI 交互。状态用功能色(success/warning/error/info),primary保留给每屏最重要的那一个动作。
字体排印:14px 基准与双字重纪律
基准字号是14px 而非 16px。企业控制台用可读性余量换信息密度:1440px 宽的窗口要同时容纳侧边栏、顶栏、八列数据表和详情面板;在 14px 下,正文行宽恰好在这些布局要求的栏宽内达到约 75 字符的视觉扫读甜区。
字体栈按操作系统 UI 字体优先排序:Apple 的-apple-system→BlinkMacSystemFont→ Windows 的Segoe UI→ Android/ChromeOS 的Roboto→Helvetica Neue→Arial,Noto Sans兜底 Linux,Emoji 回退保持精简。代码字体按同序使用SFMono-Regular、Consolas、Liberation Mono、Menlo、Courier。
产品界面只出现两个字重:400(正文、控件、菜单项、Tab 标签)与 600(fontWeightStrong——标题、表头及一切 title 级文本)。细体(100–300)、粗体(700+)与斜体不出现在界面外壳里——它们与系统追求的"平静、确定"基调相冲突;斜体仅在长文档正文中可接受。选中/激活态的视觉强调来自颜色与描边(border、underline),而非字重。
front-matter 中固化的字阶令牌(全部继承 14px 基准派生):
| 令牌 | 字号/字重/行高 | 对应种子令牌 |
|---|---|---|
display-lg | 38px / 600 / 46px | — |
headline-lg | 30px / 600 / 38px | — |
headline-md | 24px / 600 / 32px | fontSizeLG一档 |
headline-sm | 20px / 600 / 28px | — |
title-lg | 16px / 600 / 24px | — |
title-md | 14px / 600 / 22px | fontSize+fontWeightStrong |
body-lg | 16px / 400 / 24px | — |
body-md | 14px / 400 / 22px | fontSize |
body-sm | 12px / 400 / 20px | fontSizeSM |
code | 13px / 400 / 20px(等宽栈) | fontFamilyCode |
行高并非拍脑袋:源码 genFontSizes.ts 中行高统一按(fontSize + 8) / fontSize计算(14px → 22px 即 1.571,与上表body-md一致),字阶梯度则按base * E^(i/5)生成后取偶数对齐,这是 front-matter 中 12/14/16/20/24/30/38 阶梯的来源。种子侧对应 seeds.ts 的fontFamily、fontFamilyCode、fontSize(默认 14)。
布局:4px 网格与三层表面模型
所有间距对齐4px 网格。六阶间距比例(unit、xs、sm、md、lg、xl→ 4 / 4 / 8 / 16 / 24 / 32px)覆盖系统中的全部 gap、gutter 与 inset。"魔法数字"(如padding: 11px、gap: 13px)不允许出现在令牌驱动的代码中;输入框 11px 水平内边距是唯一的例外——该设计早于 4px 网格,迁移 1px 会牵动数百万存量屏幕,因此保留为历史债。种子令牌对应 seeds.ts 中的sizeUnit(默认 4)、sizeStep(默认 4)与controlHeight(默认 32),派生尺寸梯度在 genSizeMapToken.ts 中按sizeUnit × (sizeStep ± n)公式生成(sizeXXL48 →sizeXXS4)。
表面采用三层模型:
bg-layout(#F5F5F5)——页面背景,环绕并承载其余一切;bg-container(#FFFFFF)——卡片、面板、表格、表单的承载面,大多数内容的居住地;bg-elevated(#FFFFFF,与bg-container同 hex)——弹窗、下拉、气泡的表面,与bg-container的区分不靠颜色而靠阴影。
规则明确:永远不要在产品代码里硬编码#FFF或#FAFAFA,读令牌。三层模型正是暗色主题算法能够翻转表面阶梯而不破坏布局的前提。
高程与动效:flat-first、阴影分级与三档时长
Ant Design 是flat-first的:层级主要靠描边与色调对比承载,阴影只出现在真正悬浮于上下文之上的表面。阴影令牌从colorShadow生成,因此同名令牌在明暗主题间自动适配。核心分级(令牌名可在 alias.ts 中检索到类型定义):
- Tertiary(
boxShadowTertiary)——浅层抬升阴影:0 1px 2px 0 rgba(0,0,0,0.05), 0 1px 6px -1px rgba(0,0,0,0.03), 0 2px 4px 0 rgba(0,0,0,0.03); - Popup(
boxShadow与boxShadowSecondary)——标准浮层阴影:0 6px 16px 0 rgba(0,0,0,0.08), 0 3px 6px -4px rgba(0,0,0,0.12), 0 9px 28px 8px rgba(0,0,0,0.05); - Card(
boxShadowCard)——卡片专用的窄扩散抬升阴影,用于卡片需要从容器中分离的场合; - 方向性阴影(
boxShadowDrawer*、boxShadowTabsOverflow*)——贴边表面与滚动暗示的专用令牌; - 气泡箭头(
boxShadowPopoverArrow)——仅用于 Tooltip/Popover 的小三角指针。
动效使用三档时长加一组命名缓动,全部以令牌形式暴露:
| 令牌 | 时长 | 适用场景 |
|---|---|---|
motionDurationFast | 0.1s | 状态变化(hover、focus、press) |
motionDurationMid | 0.2s | 组件内部过渡(collapse、fade) |
motionDurationSlow | 0.3s | 表面级变化(modal 进入、drawer 滑入) |
缓动函数预定义为motionEaseInOut、motionEaseOut、motionEaseIn、motionEaseOutBack、motionEaseOutCirc等,与 seeds.ts 中的motionUnit、motionBase及motionEase*种子一一对应。规则:不要随手挑transition-timing-function;若需求匹配不到已有缓动,用motionEaseInOut然后继续。
形状:圆角的组件级纪律
默认圆角是6px——足够圆以显得现代友好,又足够小,使 32px 高的按钮仍呈现干净的近矩形轮廓,适配高密度表单。按组件类别的圆角规则(对应 front-matter 的rounded令牌:none0 /sm2 /md4 /DEFAULT6 /lg8 /xl16 /full9999px):
- 控件(button、input、select、下拉触发器)—— 6px(
rounded.DEFAULT); - 表面(card、modal、drawer、notification)—— 8px(
rounded.lg); - 标签与小胶囊—— 4px(
rounded.md); - Tooltip 与 Popover—— 4px(
rounded.md)。
全圆角(rounded.full,9999px)保留给圆形头像、徽标与圆点,不用于按钮或标签;直角(0px)保留给表格与分段控件的内边缘。相邻元素混用圆角是坏味道:8px 圆角的卡片里不应装 16px 圆角的按钮。
组件原型:最常见的表面与状态
DESIGN.md 将系统中最常见的表面与状态固化为组件原型,每个条目映射到 front-matter 中的令牌引用(components段),并给出使用纪律:
| 原型 | 关键令牌 | 规则 |
|---|---|---|
| Button (primary) | 实心primary填充、白字、32px 高、6px 圆角;hover#4096FF、active#0958D9;内边距0 15px | 每屏唯一主导动作;不要在同一个决策面叠放两个 primary 按钮 |
| Button (default) | 白底暗字、1px 描边;hover 文字变#4096FF、描边同色 | 次级动作,其余按钮降级到 default |
| Input field | 32px 高与按钮对齐;1px 描边;focus 时描边加粗为primary并加内发光;占位符用on-surface-disabled;内边距4px 11px | 11px 水平内边距是 4px 网格前的历史保留值 |
| Select | 与 Input 视觉一致 | 触发器在交互前必须"看起来像输入框" |
| Card | 白色表面、8px 圆角、可选boxShadowCard;内边距 24px | 容器主力;嵌套控件保持 16px 间距 |
| Modal | 与 Card 同表面同圆角;二级阴影层级;居中于rgba(0,0,0,0.45)遮罩 | 正文内边距 20px(上下)× 24px(左右) |
| Menu(选中项) | #E6F4FF背景、primary文字 | 导航"你在这里"的唯一视觉线索 |
| Tabs(激活项) | primary文字 + 2pxprimary下划线;未激活为on-surface-variant | 任何状态下 Tab 都不带背景填充 |
| Table(表头行) | surface-container背景、title-md(14px/600)、内边距 16px | 数据行仅 hover 高亮、默认不做斑马纹——系统信任用户能读密集数据 |
| Tag | 4px 圆角、12px 字、预置低饱和浅染填充、内边距0 7px | 仅做分类标签,关键状态用 Alert 或 Badge |
| Alert(success/warning/error/info) | 浅色语义底(#F6FFED/#FFFBE6/#FFF2F0/#E6F4FF)+ 正常文本色、8px 圆角、内边距8px 12px | 状态由图标与底色传达,而非低对比度彩色正文 |
| Badge 状态点 | error实心、rounded.full、6×6px | 紧凑状态指示;可访问性关键流程中圆点不能替代文字 |
| Tooltip | rgba(0,0,0,0.85)底、白字、4px 圆角、内边距6px 8px | 高对比反色表面;位置永远由框架决定,禁止手动钉死 |
| Dropdown 项 hover | surface-container填充、文字色不变 | hover 提示本身已经足够 |
Do's and Don'ts:十条裁决规则
DESIGN.md 给出的可执行纪律(原文完整继承):
- Do用四大设计价值观做裁决。两方案冲突时,让用户状态更确定、更易读的方案胜出。
- Don't在同一表面叠放两个
primary色按钮。只选一个,其余降级为default。 - Do从
colors.surface、colors.surface-container、colors.surface-layout读取表面。它们反映三层模型。 - Don't硬编码
#FFFFFF或#FAFAFA。hex 是偶然的,角色才是本质。 - Do对找不到更具体令牌的组件级过渡使用
motionDurationMid(0.2s)。 - Don't发明自定义
cubic-bezier曲线。用命名缓动。 - Do把预置色板(
blue~lime)保留给标签、图表与分类可视化。 - Don't为一次性 UI 表面在预置色板之外铸新强调色。如果某个屏幕"似乎需要"它,多半是布局需要重做。
- Do通过间距比例把每个 gap、inset、gutter 对齐到 4px 网格。
- Don't在产品代码里用魔法数字。若比例缺了你需要的档位,该重新审视的是设计,而不是 1px 覆盖。
源码纵深:DESIGN.md 令牌在 theme 模块中的实现链路
DESIGN.md front-matter 中的每个值都是由defaultAlgorithm产出的默认值。从源码结构看,这套主题机制分三层,全部位于 components/theme/:
种子层(Seed Token):seeds.ts 定义了
SeedToken接口——colorPrimary、colorSuccess、colorWarning、colorError、colorInfo、colorTextBase、colorBgBase、colorLink、fontFamily、fontFamilyCode、fontSize、lineWidth、borderRadius、sizeUnit、sizeStep、controlHeight、zIndexBase、zIndexPopupBase、opacityImage、motionUnit、motionBase、motionEase*族,以及风格开关wireframe(默认 false)、focusOutline(默认 true)、motion(默认 true)。文件顶部的注释写着 "DO NOT MODIFY THIS. PLEASE CONTACT DESIGNER"——种子层是设计系统最不容越权的边界。派生层(Map/Alias Token):default/index.ts 的
derivative()依次执行"预置色 10 级展开(generate())→genColorMapToken(主色/语义色/中性色映射)→genFontMapToken(字阶)→genSizeMapToken(尺寸梯度)→genControlHeight(控件高度梯度)→genCommonMapToken(阴影、zIndex、动效等)"。中性色由generateNeutralColorPalettes(colorBgBase, colorTextBase)生成,即正文中 "rgba(0,0,0,α) 阶梯" 的实现来源。darkAlgorithm(components/theme/themes/dark/)与compactAlgorithm复用同一骨架:例如 compact 的 derivative 把字号基准降到fontSizeSM(12px)并令controlHeight - 4(28px),再重算尺寸与字阶梯度。消费层:components/theme/index.tsx 以单个
theme对象对外导出defaultSeed、useToken、defaultAlgorithm、darkAlgorithm、compactAlgorithm与getDesignToken;useToken是 React 内的令牌消费入口,getDesignToken.ts 提供 React 之外(如 SSR、脚本)按ThemeConfig解析令牌的纯函数路径。cssVar与zeroRuntime开关则定义在 context.ts 中,前者让样式以 CSS 变量输出,后者在禁用运行时样式生成时与预构建/提取的 CSS 配合使用。令牌派生的正确性由 components/theme/tests/token.test.tsx 回归守护。
定制指南:五层官方主题能力
DESIGN.md 的 Customization 一节指出:Ant Design 的主题化远不止 Design Token 替换,它包含算法派生、组件作用域覆盖、动态切换、嵌套主题作用域、CSS 变量输出、静态令牌消费与零运行时 CSS 提取。主入口是ConfigProvider的theme属性,完整运行时 API 见 Customize Theme 中文文档:
种子令牌覆盖。向
ConfigProvider传theme.token即可替换任意种子。主色与语义种子(colorPrimary、colorSuccess、colorWarning、colorError、colorInfo)会展开为派生梯度;colorBgBase与colorTextBase驱动中性表面与文本;间距、圆角、字号种子同理。算法切换。
theme.algorithm用于替换派生逻辑。defaultAlgorithm、darkAlgorithm、compactAlgorithm可单独使用,也可以数组形式组合——不要手动反色:算法负责处理非线性色板、表面、阴影与尺寸关系(对应源码中三个DerivativeFunc的组合调用)。组件级覆盖。
theme.components.Button(或任意组件的令牌命名空间)可只覆盖单个组件的 Component Token 与被消费的 Alias Token 而不影响其他组件;组件配置中的algorithm可让该组件在覆盖时仍遵循种子令牌关系。运行时作用域。改
ConfigProvider.theme即可动态切换主题;嵌套ConfigProvider创建局部主题并从父级继承未改动的令牌。注意:message.xxx、Modal.xxx、notification.xxx等静态 API不会自动获得外层上下文,需要主题化静态反馈时应使用 hook 形式 API、App组件或显式的上下文持有者。令牌消费与输出。React 内用
theme.useToken(),React 外用theme.getDesignToken()消费解析后的令牌;需要 CSS 变量时用theme.cssVar;必须禁用运行时样式生成时,用theme.zeroRuntime配合预构建或提取的 CSS。
最后一条定制纪律值得原样保留:做自定义主题时,先保住 Ant Design 的交互结构、密度、状态反馈与组件语义,再改动最小的种子集——通常就是colorPrimary、状态色、borderRadius、fontFamily、fontSize与中性表面基础色。品牌页可以看起来不同,但表单、表格、导航、浮层、聚焦态与校验反馈必须仍然"像 Ant Design"。避免生成绕过令牌、算法、theme.components、CSS 变量或提取静态样式的自定义 CSS 规则;如果一个主题无法通过上述官方层表达,应把它当作设计系统的扩展需求,而不是某页的一次性样式。
小结
DESIGN.md 把 Ant Design v6 默认浅色主题压缩为一份机器可读、人类可执行的契约:颜色上"种子决定梯度、角色先于 hex",字体上"14px 基准 + 双字重纪律",布局上"4px 网格 + 三层表面",高程上"flat-first + 命名阴影与缓动",形状上"圆角按组件类别分配"。仓库中的 components/theme/ 实现与 tests/design-md.test.ts 回归测试则证明这份契约不是纸面规范,而是被defaultSeed→defaultAlgorithm→useToken全链路执行的活代码——这正是它既能约束人类开发、又能驱动 AI 设计工具的原因。
【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/GitHub_Trending/an/ant-design
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考