1. 从一张草图到一套系统:diagram-design 到底在解决什么问题
第一次听到“diagram-design”这个词,很多人会下意识觉得它只是“画图”的另一种说法。但真正在项目里被图表折磨过的人都知道,画一张图不难,难的是让一百张图看起来像同一个人画的,难的是改一个节点颜色要翻遍十几个文件,难的是产品经理说“这个流程再加一个分支”时你不用重新拖半小时的连线。diagram-design 要处理的,正是这一整套围绕图表的设计系统化问题,而不是单纯的绘图技巧。
我把它理解成三层意思的叠加。第一层是图的语义设计,也就是这张图到底要表达什么关系,是流程、是状态、是时序还是层级;第二层是图的视觉设计,包括配色、字体、间距、连线样式、节点形状这些看得见的东西;第三层是图的生产设计,也就是用什么工具、什么格式、怎么版本管理、怎么让非设计角色也能参与维护。这三层任何一层塌了,最后交付出来的图都会变成“一次性用品”——发出去那一刻挺好看,第二天要改就没人愿意碰。
这套东西适合谁?如果你只是偶尔画一张示意图发群里,那确实用不上这么重的思路。但只要你的项目里图表数量超过十张、参与人数超过两个、生命周期超过一个月,diagram-design 的价值就会立刻显现。它特别适合技术文档作者、产品经理、系统架构师、以及那些需要长期维护一套可视化规范的小团队。哪怕你用的是最普通的绘图工具,只要脑子里有这套框架,产出质量也会明显不一样。
我见过太多团队在图表上重复造轮子:A 同学用一套配色画架构图,B 同学用另一套画流程图,C 同学直接截图贴进文档,最后整个知识库看起来像拼贴画。diagram-design 的核心主张就是把这些散落的决策收拢成一套可复用的规则,让“画图”从个人手艺变成团队资产。下面我会把这套思路拆开,从整体设计、核心细节、实操落地到问题排查,一层层讲清楚怎么把它跑起来。
2. 整体设计思路:为什么图表也需要一套设计系统
2.1 图表失控的三个典型信号
在动手设计任何规则之前,先要能识别“图表已经失控”这件事。我总结下来有三个信号特别准。第一个信号是同一份文档里出现三种以上不同的圆角半径,这说明没有人定义过节点的基础样式,每个人都在凭手感拖。第二个信号是改一个颜色需要打开超过五个文件,这说明样式没有集中管理,颜色是硬编码在各个图里的。第三个信号是新成员画的第一张图和团队风格完全对不上,这说明规则只存在于老成员的脑子里,没有形成可传递的规范。
这三个信号背后其实是同一个根因:图表的决策没有被抽象出来。每一张图都在重新做一遍“用什么颜色、什么字体、什么间距”的决定,重复劳动不说,还必然产生偏差。diagram-design 的第一步,就是把这些重复决策抽成一套设计令牌(design token)——颜色、字号、间距、线宽、圆角,全部变成有名字的变量,而不是散落的具体数值。
提示:不要一上来就追求大而全的规范。先把你最近画过的五张图摆在一起,找出其中重复出现的视觉决策,那些才是真正值得抽象的部分。抽象过度比不抽象更麻烦。
2.2 语义层与视觉层为什么要分开
很多人的图表设计是从“选一个好看的模板”开始的,这其实把语义和视觉混在了一起。diagram-design 强调先定语义、再定视觉,原因是这两者的变更频率完全不同。语义层描述的是“这个节点是一个服务还是一个数据库”,它相对稳定;视觉层描述的是“服务用蓝色圆角矩形”,它可能因为品牌升级、暗色模式适配而频繁变化。如果两者耦合,每次换配色都要重新理解图的结构,成本极高。
举个具体例子。假设你有一套微服务架构图,语义上节点分为“网关、服务、存储、外部依赖”四类。如果你在绘图时直接给每类节点指定了具体颜色,那么当团队决定把主色从蓝色换成绿色时,你需要逐个节点去改。但如果你先定义了node-gateway、node-service这样的语义标签,再把颜色绑定到标签上,换色只需要改一处映射。这就是语义与视觉分离带来的直接收益。
在实际操作中,我通常会用一张简单的映射表来管理这层关系。表格左边是语义角色,右边是对应的视觉令牌。这张表本身就是 diagram-design 的核心资产,它让“这张图该长什么样”变成一个可以查阅、可以讨论、可以版本化的问题,而不是靠某个人的审美直觉。
| 语义角色 | 形状 | 填充令牌 | 边框令牌 | 文字令牌 |
|---|---|---|---|---|
| 入口/网关 | 圆角矩形 | fill-primary | stroke-strong | text-on-primary |
| 内部服务 | 圆角矩形 | fill-surface | stroke-default | text-default |
| 数据存储 | 圆柱体 | fill-muted | stroke-default | text-default |
| 外部依赖 | 虚线矩形 | fill-transparent | stroke-dashed | text-muted |
| 异步消息 | 平行四边形 | fill-accent | stroke-accent | text-on-accent |
这张表看起来简单,但它解决了一个大问题:当两个人分别画图时,只要他们都查这张表,产出的图在语义层面就是一致的。视觉细节可以后续统一调整,但结构不会跑偏。
2.3 为什么选择“约束优先”而不是“自由优先”
绘图工具通常默认给你无限的自由:任何颜色、任何形状、任何位置。这种自由在画单张图时是优势,在维护一套图时是灾难。diagram-design 的思路是约束优先——主动限制可选范围,用更少的选项换取更高的一致性。这听起来反直觉,但实际用起来会发现,约束反而让画图更快,因为决策成本降低了。
具体怎么做约束?我的做法是给每一类视觉属性设定一个封闭集合。比如颜色只允许使用调色板里的八个令牌,字号只允许三档(标题、正文、注释),线宽只允许两档(主连线、辅助连线)。当你在绘图时发现需要一个“新颜色”,第一反应不应该是去调色盘里随便选,而是问自己:现有的八个令牌里真的没有一个合适的吗?大多数时候答案是有的,只是你还没试。
这种约束优先的思路还有一个隐藏好处:它让图表在暗色模式、打印场景、高对比度无障碍场景下的适配变得可行。如果你的颜色是封闭集合,你只需要为这八个令牌各准备一套暗色值,整批图就能整体切换。如果颜色是散落的,那暗色模式基本等于重画。这也是为什么我坚持认为,diagram-design 不是审美问题,而是工程问题。
3. 核心细节解析:图表设计系统的关键构件
3.1 设计令牌的命名与分层
设计令牌是整套系统的地基,命名一旦混乱,后面全乱。我踩过的坑是早期用blue-1、blue-2这种描述性命名,结果品牌色一换,名字和实际颜色对不上,非常尴尬。后来改成语义化命名,比如color-primary、color-surface、color-danger,名字描述用途而不是外观,这样即使具体色值变了,名字依然成立。
令牌还需要分层。我通常分三层:基础层(原始色值、字号数值)、语义层(primary、surface、muted)、组件层(node-fill、edge-stroke)。基础层是调色板,语义层是用途映射,组件层是具体图表元素的绑定。三层之间单向依赖,基础层不依赖任何东西,语义层依赖基础层,组件层依赖语义层。这样当你要做主题切换时,只需要替换基础层,上面两层自动跟着变。
# 基础层 palette: blue-500: "#2F6FED" gray-100: "#F5F6F8" gray-700: "#3A3F47" # 语义层 semantic: color-primary: "{palette.blue-500}" color-surface: "{palette.gray-100}" color-text: "{palette.gray-700}" # 组件层 component: node-fill: "{semantic.color-surface}" node-stroke: "{semantic.color-primary}" node-text: "{semantic.color-text}"这种分层看起来有点绕,但它的价值在规模化时会爆发。假设你有五十张图,某天需要把主色调整 10% 的明度,你只需要改基础层的一个值,五十张图全部同步。如果没有分层,这就是五十次手工操作,而且一定会漏掉几张。
3.2 节点与连线的视觉语法
节点和连线是图表里出现频率最高的两个元素,它们的视觉语法必须最先固定下来。节点方面,我建议固定形状语义:矩形代表处理单元,圆柱代表存储,菱形代表判断,平行四边形代表消息,虚线框代表外部系统。这套映射一旦定下来,读者看图的认知负担会大幅降低,因为他们不需要每次重新理解形状含义。
连线方面,关键是区分主次关系。主流程用实线加粗,辅助关系用细实线,异步或可选路径用虚线。箭头样式也要统一,我通常只用一种箭头(实心三角),避免混用多种箭头造成视觉噪音。连线上的标签位置也要规定,要么统一在线的中点上方,要么统一在起点附近,不能一张图一个样。
注意:连线的交叉是图表可读性的头号杀手。与其花时间美化交叉,不如花时间调整节点位置减少交叉。如果实在无法避免,使用“跳线”符号(一条小弧线跨过另一条线)比直接交叉更清晰,但前提是全图统一使用,不能有的跳有的不跳。
这里有个容易被忽略的细节:连线与节点的连接点。很多工具默认从节点中心连线,导致线被节点挡住。正确的做法是让连线从节点边缘出发,并且连接点位置要稳定——要么固定在上下左右四个中点,要么根据相对位置自动选择。这个细节看起来小,但它直接决定了图看起来是“专业”还是“随手画的”。
3.3 布局网格与间距节奏
图表的“高级感”很大程度上来自间距的一致性。人眼对不齐的东西极其敏感,哪怕只差两个像素,也会觉得别扭。diagram-design 要求所有节点对齐到一套隐式网格上,比如以 8 像素为基准单位,节点的位置、大小、间距都是 8 的倍数。这样即使你没有刻意对齐,整体也会显得整齐。
间距节奏还体现在分组上。相关的节点应该靠得更近,不相关的节点之间留出更大的空隙。这其实就是格式塔心理学里的“接近性原则”——距离近的元素会被自动视为一组。我在画架构图时,会先按功能域把节点分成几个簇,簇内间距用 16 像素,簇间间距用 48 像素,这样读者一眼就能看出系统的模块划分,不需要额外的分组框。
布局这件事,我的经验是先手动、后自动。自动布局工具(比如力导向布局)适合探索性场景,但最终交付的图一定要手动微调。因为自动布局不理解语义,它可能把两个强相关的节点拉得很远,或者把不相关的节点挤在一起。手动调整虽然费时间,但换来的是读者理解成本的下降,这笔账是划算的。
3.4 文字层级与标注规范
图表里的文字分三类:节点标题、节点描述、连线标注。这三类的字号、字重、颜色必须有明确区分,否则读者分不清主次。我的做法是节点标题用最大字号加中等字重,节点描述用小一号字号加常规字重且颜色略淡,连线标注用最小字号且颜色最淡。这样即使信息很多,视觉层次依然清晰。
字体选择上,我强烈建议用系统无衬线字体,比如各类操作系统自带的默认无衬线字体。原因是图表经常需要在不同设备、不同软件里打开,如果用了特殊字体,在别人电脑上可能变成默认字体,导致排版错乱。系统字体虽然不够个性,但胜在稳定,而图表的首要目标是传达信息,不是展示字体品味。
标注规范里还有一个细节:单位和缩写。如果图里出现“100ms”“2GB”这类带单位的值,要统一单位格式,不能有的写“ms”有的写“毫秒”。缩写也要统一,比如“数据库”要么全写“DB”,要么全写“数据库”,不能混用。这些细节单看很小,但累积起来就是专业和业余的分界线。
4. 实操落地:从零搭建一套可维护的图表工作流
4.1 工具选型:文本驱动还是画布驱动
搭建工作流的第一步是选工具,这里有个关键分叉:文本驱动(用代码描述图,比如各类图表 DSL)还是画布驱动(用鼠标拖拽,比如各类在线绘图工具)。两者没有绝对优劣,取决于你的使用场景。文本驱动的优势是版本管理友好、批量修改方便、适合纳入代码仓库;画布驱动的优势是上手快、适合非技术角色、适合探索性绘制。
我的建议是混合使用:核心的、需要长期维护的图用文本驱动,一次性的、探索性的图用画布驱动。文本驱动的图可以进版本控制,每次修改都有 diff 记录,谁改了什么一目了然。画布驱动的图适合快速沟通,但不要指望它们能长期维护。很多团队的痛苦就在于用画布工具画了需要长期维护的图,结果每次修改都像考古。
| 维度 | 文本驱动 | 画布驱动 |
|---|---|---|
| 上手门槛 | 较高,需要学语法 | 低,拖拽即可 |
| 版本管理 | 原生支持 diff | 通常只能存二进制 |
| 批量修改 | 改一处全局生效 | 逐个手工调整 |
| 协作方式 | 代码评审 | 实时协同 |
| 适合场景 | 架构图、流程图、状态机 | 白板讨论、草图、演示 |
选型时还要考虑导出格式。我优先选择支持 SVG 导出的工具,因为 SVG 是矢量格式,放大不糊,还能用文本编辑器直接改。PNG 适合快速分享,但不适合长期存档,因为分辨率固定,未来高分辨率场景下会过时。PDF 适合打印,但编辑性差。我的习惯是源文件用文本格式,交付时导出 SVG,需要快速预览时再导一份 PNG。
4.2 目录结构与版本管理
一旦图表数量上来了,目录结构就变得重要。我的做法是按领域分目录,而不是按图类型分。比如architecture/、flows/、states/,每个目录下放对应的源文件和导出文件。这样当你要找“订单流程”的图时,直接去flows/下找,而不是在一堆flow-1、flow-2里翻。
版本管理方面,文本驱动的图天然适合 Git。我通常会把源文件和导出文件分开管理:源文件进版本控制,导出文件通过构建脚本生成,不手动提交。这样仓库里只有源文件,diff 干净,不会因为导出文件的二进制变化产生噪音。构建脚本可以用简单的命令行工具,每次源文件变更时自动重新导出。
# 示例:批量导出所有图表为 SVG for f in diagrams/**/*.mmd; do out="${f%.mmd}.svg" render-tool "$f" -o "$out" done提示:导出文件建议加入
.gitignore,只在发布时生成。这样仓库体积小,评审时只看源文件变更,效率高很多。如果团队需要在线预览,可以搭一个简单的静态站点,构建时自动渲染。
4.3 从草图到成图的完整流程
我实际画一张图的流程通常是这样的。第一步是语义梳理,在白板或纸上把节点和关系列出来,这时候完全不考虑视觉,只关心逻辑对不对。第二步是选择模板,根据图的类型(流程、架构、状态)选一个已有的骨架,避免从零开始。第三步是填充内容,把节点和连线按语义标签填进去,这时候视觉样式自动应用,不需要手动调。第四步是布局微调,手动调整节点位置减少交叉、优化分组。第五步是导出与评审,导出 SVG 发给相关人确认,收集反馈后回到源文件修改。
这个流程里最关键的是第一步和第三步的分离。很多人一上来就打开绘图工具开始拖,边拖边想逻辑,结果逻辑还没理清,视觉已经做了一堆无用功。先把语义理清楚,再套视觉模板,效率会高很多。我自己的经验是,一张中等复杂度的架构图,语义梳理占 40% 时间,填充和微调占 60%,但如果跳过语义梳理,后面会反复返工,总时间反而更长。
4.4 让非设计角色也能参与维护
图表维护最大的痛点往往不是设计本身,而是“只有一个人会改”。如果图表系统只有原作者能维护,那它迟早会腐烂。diagram-design 的一个目标就是降低维护门槛,让产品经理、测试、甚至运营都能参与修改。做到这一点的关键是把修改操作标准化:改文字就是改文字,改颜色就是改令牌,不需要理解整个系统。
具体做法是提供片段模板。比如常用的“服务节点”“数据库节点”“消息队列节点”都做成可复制的代码片段,维护者只需要复制片段、改文字、连线,不需要从零画形状。再配合一份简短的“修改指南”,说明哪些能改、哪些不能改、改完怎么导出,基本上半小时就能培训出一个能维护图表的人。
这里有个反直觉的经验:不要追求所有人都能改所有东西。更好的分工是让少数人维护令牌和模板,多数人只负责填充内容。这样既保证了视觉一致性,又降低了参与门槛。令牌和模板的维护者不需要很多,一两个对视觉有感觉的人就够了,但他们要负责定期审查,确保没有人在模板之外乱加样式。
5. 常见问题与排查技巧实录
5.1 图表看起来“不专业”的排查清单
很多人觉得自己的图“说不上哪里不对,就是不好看”,其实问题通常出在几个固定地方。我整理了一份排查清单,按优先级从高到低检查,基本能解决八成问题。
| 排查项 | 常见问题 | 修复方法 |
|---|---|---|
| 对齐 | 节点边缘参差不齐 | 开启网格吸附,统一对齐基准 |
| 间距 | 有的地方挤有的地方空 | 统一使用 8 的倍数间距 |
| 颜色 | 颜色数量超过五种 | 收敛到调色板令牌 |
| 字体 | 字号超过三档 | 合并为标题/正文/注释三档 |
| 连线 | 交叉过多、箭头样式不一 | 调整布局,统一箭头 |
| 留白 | 图边缘太挤 | 四周留出至少 24 像素边距 |
这份清单我用了很久,基本上任何一张“感觉不对”的图,逐项检查下来都能找到具体原因。最容易被忽略的是留白,很多人把图画得满满当当,觉得信息密度高是好事,其实留白是让图“呼吸”的关键。图边缘留出足够空间,读者视线才有落点,不然会觉得很压抑。
5.2 修改一张图导致其他图错乱的预防
这是文本驱动方案里最常见的事故:改了一个共享令牌,结果所有引用它的图都变了样。预防方法有两个。第一是令牌变更要评审,不能随手改,因为它的影响面是全局的。第二是导出前做视觉回归,把改动前后的导出图并排对比,确认没有意外变化。
我自己的做法是给令牌加版本号,重大变更时升版本,旧图继续引用旧版本,新图用新版本,逐步迁移。这样避免了“一刀切”带来的连锁反应。虽然管理多个版本有点麻烦,但比起某天早上发现所有图都变色了,这点麻烦是值得的。
注意:如果你用的是支持主题继承的工具,务必确认继承链是单向的。我见过循环继承导致渲染失败的案例,排查起来非常痛苦。设计令牌的依赖关系应该是树状,不能有环。
5.3 团队协作中的样式冲突处理
多人协作时,样式冲突几乎不可避免。A 同学觉得这个节点应该用蓝色,B 同学觉得应该用灰色,最后图里两种颜色都有。处理这类冲突的关键是把审美问题转化为规则问题。不要争论“蓝色好看还是灰色好看”,而是回到语义表:这个节点属于哪一类?语义表里对应的令牌是什么?按表来,不按个人喜好来。
如果语义表里确实没有覆盖这种情况,那说明语义表需要扩展,这时候应该开一个短会讨论新增哪一类,而不是让个人临时决定。扩展语义表时要考虑未来,尽量选一个能覆盖一类场景的抽象,而不是只为当前这一个节点打补丁。我见过语义表膨胀到几十个令牌的案例,那其实说明抽象层次没找对,需要重新归类。
5.4 导出与分享环节的坑
导出环节的坑主要集中在字体丢失和尺寸失真上。字体丢失是因为导出环境没有安装源文件用的字体,解决办法是导出时把文字转成路径,或者坚持用系统字体。尺寸失真通常是因为导出时没有指定视口,导致图被裁剪或留白过多。我的习惯是导出前先设定一个固定的画布尺寸,所有图都按这个尺寸导出,这样在文档里排列时大小一致,看起来整齐。
分享环节的坑主要是版本混乱。同一张图可能有多个版本在流传,别人拿到的是旧版。解决办法是给导出文件加版本标识,比如文件名里带日期或版本号,并且在图内也标注版本信息。这样即使文件被转发多次,也能追溯来源。虽然有点繁琐,但比起用错版本导致的沟通事故,这点成本完全可以接受。
6. 我在这套方法上踩过的坑与最终沉淀
回过头看,我在 diagram-design 这条路上最大的教训是过早追求完美规范。早期我花了两周设计了一套自认为很完整的令牌体系,结果实际画图时发现一半的令牌根本用不上,而真正需要的几个又没定义。后来我改成“用多少定多少”,先画图,遇到重复决策再抽象成令牌,这样长出来的规范才是真正被使用的规范,而不是纸上谈兵。
第二个教训是忽视了非技术角色的体验。我曾经把整套系统设计得很“工程化”,结果产品经理完全不知道怎么改图,最后还是得我来改。后来我加了一层简单的片段模板和修改指南,情况才好转。这让我意识到,图表系统的成功标准不是设计得多优雅,而是有多少人愿意用、能够用。
第三个体会是版本管理要趁早。我早期有几张核心架构图没有进版本控制,后来想追溯某次改动的原因,完全找不到记录。从那以后,所有需要长期维护的图我都强制进版本控制,哪怕一开始觉得“这张图不会再改了”。事实证明,没有哪张图是真正不会再改的。
最后分享一个我一直在用的小技巧:每季度做一次图表审计。把所有还在使用的图过一遍,检查是否还符合当前规范,是否有过时的内容,是否有可以合并的重复图。这个习惯帮我清理了不少“僵尸图”,也让整套系统始终保持活力。图表和代码一样,不维护就会腐烂,定期审计是最低成本的维护手段。