Mermaid 流程图编辑器
流程图展示控制如何在一个流程中流动:有哪些步骤、在哪里分支、分支又在哪里汇合。当决策的先后顺序才是重点时用它——部署流水线、请求路径、审批路线。如果重点是谁在什么时候和谁通信,那该用时序图。
带两条失败分支的 CI 流水线
这是本站大多数流程图最初的样子:一条线性的正常路径,加上从中岔出去的决策节点。注意最后一个节点的引号——标签里出现括号就必须加引号,这也是流程图最常见的错误。
flowchart TD
Push[推送到 main] --> Lint[代码检查与类型检查]
Lint --> Test{测试通过?}
Test -->|否| Fail[在群里通知提交者]
Test -->|是| Build[构建容器镜像]
Build --> Scan{漏洞扫描通过?}
Scan -->|否| Block["阻止发布 (需人工确认)"]
Scan -->|是| Deploy[部署到生产环境]
Deploy --> Smoke[执行冒烟测试]
Smoke --> Done[发布完成]实例讲解
1. 最小可用的流程图
两个节点加一个箭头。`TD` 表示从上到下;`LR` 表示从左到右,凡是宽大于高的图通常都更适合用它。
flowchart TD
请求[收到请求] --> 响应[返回响应]2. 带分支标签的判断
花括号生成菱形。竖线之间的文字标注的是这条边,而不是节点——这个区别在下面的报错部分很关键。
flowchart TD
Start[收到请求] --> Auth{令牌有效?}
Auth -->|是| Handler[执行处理逻辑]
Auth -->|否| Reject[返回 401]
Handler --> Done[返回 200]3. 让形状承载含义
形状是给流程图增加信息最省事的办法。圆角表示起止,菱形表示判断,圆柱表示存储。
flowchart LR
Start([任务被调度]) --> Read[(从 Postgres 读取)]
Read --> Check{有待处理数据?}
Check -->|没有| Stop([正常退出])
Check -->|有| Work[/转换数据/]
Work --> Write[(写入 S3)]
Write --> Stop4. 用子图按归属分组
子图会给相关节点画一个框。最有价值的分组方式往往不是按流程阶段,而是按归属——哪个团队或哪个服务负责哪一段,这样交接点就显现出来了。
flowchart TD
subgraph client [浏览器]
UI[用户提交表单]
end
subgraph api [订单服务]
Validate[校验请求数据]
Persist[写入订单记录]
end
subgraph async [后台任务]
Email[发送确认邮件]
Invoice[生成发票]
end
UI --> Validate
Validate --> Persist
Persist --> Email
Persist --> Invoice5. 有明确出口的重试循环
流程图处理环路毫无问题,而重试循环正是它发挥价值的地方——图能一眼看出这个循环到底有没有出口。
flowchart TD
Send[发送 Webhook] --> Result{返回 2xx?}
Result -->|是| Ack[标记为已送达]
Result -->|否| Count{尝试次数 < 5?}
Count -->|是| Wait[指数退避等待]
Wait --> Send
Count -->|否| Dead[移入死信队列]流程图语法速查
下面全部只适用于流程图。箭头写法尤其不能套用到其他图类型上——时序图的 `->>` 在这里会直接报语法错误。
| 语法 | 含义 |
|---|---|
| flowchart TD | 自上而下。也可写 TB。流程的常规阅读顺序。 |
| flowchart LR | 从左到右。也可写 RL。适合宽而浅的流程。 |
| A[文字] | 矩形——普通步骤。 |
| A(文字) | 圆角矩形。 |
| A([文字]) | 体育场形——习惯上表示起点或终点。 |
| A[(文字)] | 圆柱——数据存储。 |
| A{文字} | 菱形——判断。 |
| A[/文字/] | 平行四边形——输入或输出。 |
| A --> B | 箭头。 |
| A --- B | 无箭头的连线。 |
| A -.-> B | 虚线箭头——习惯上表示异步或可选。 |
| A ==> B | 粗箭头——习惯上表示主路径。 |
| A -->|文字| B | 带标签的边。标签里有括号时要加引号。 |
| A["文字 (含括号)"] | 加引号的标签——凡是括号、引号或会被当成形状语法的字符都需要。 |
| subgraph 名称 [标题] ... end | 把节点框进一个带标题的分组,`end` 结束。 |
| %% 注释 | 注释行,不会被渲染。 |
真正会让流程图报错的六个问题
每一条都用本站实际使用的渲染器(Mermaid 11.12.2)复现过。把出错版本粘进编辑器,你会看到完全一样的报错;修正版本则能正常渲染。读 Mermaid 报错最快的办法是看最末尾——`got` 后面就是解析器卡住的那个标记。
你会看到
Parse error,结尾是:got 'PS'
原因
方括号标签里出现了左圆括号。圆括号本身是形状语法——`A(文字)` 表示圆角节点——所以方括号内的裸括号会被当成形状的开头。
解决办法
把整个标签用双引号包起来,引号内的一切都按纯文本处理。
flowchart TD
A[重试 (最多 5 次)] --> B[完成]flowchart TD
A["重试 (最多 5 次)"] --> B[完成]你会看到
Parse error,结尾是:got 'STR'
原因
标签中间出现了双引号。解析器把它当作字符串的开头,然后在应该出现配对引号的位置撞上了方括号。
解决办法
在双引号包裹的标签内改用单引号,或把该字符写成 `#quot;`。
flowchart TD
A[状态为 "待处理"] --> B[完成]flowchart TD
A["状态为 '待处理'"] --> B[完成]你会看到
Parse error,结尾是:got 'end'
原因
把 `end` 用作了节点 ID。小写的 `end` 用于结束子图,所以解析器在应该出现节点的位置看到了块结束符。这个坑很常见,因为“end”正是最后一个节点最自然的名字。
解决办法
首字母大写,或者给节点一个 ID,把这个词放进标签里。
flowchart TD
Start[开始] --> endflowchart TD
Start[开始] --> End[已结束]你会看到
在你命名节点的那一行报 Parse error
原因
节点 ID 里带了空格。ID 是箭头前面的那个标记,空格会把它截断,解析器就剩下一个无处安放的词。
解决办法
用单个词作 ID,把可读文字放进标签。
flowchart TD
auth service --> user dbflowchart TD
auth[认证服务] --> db[(用户数据库)]你会看到
在两条竖线之间的边标签处报 Parse error
原因
边标签里出现了括号。`|…|` 和节点标签的限制一样——括号在那里仍是语法,不是文本。
解决办法
把边标签也加上引号。
flowchart TD
A -->|是 (总是)| Bflowchart TD
A -->|"是 (总是)"| B你会看到
Lexical error on line 1. Unrecognized text.
原因
方向写错了。流程图只接受 TB、TD、BT、LR、RL,写错会在词法阶段就失败,此时还没读到任何节点——所以报错指向第 1 行而不是你真正写错的地方。
解决办法
用这五个之一。TD 和 LR 基本够用。
flowchart TOPDOWN
A --> Bflowchart TD
A --> B渲染须知
以下都是针对本站所用的 Mermaid 11.12.2 实测得出的,不是从文档抄来的。当流程图不再是玩具时,这些才是真正影响你的地方。
中文标签比英文更紧凑,图反而更窄
这一点和直觉相反,值得记住。一个汉字的显示宽度大约是拉丁字母的两倍,但表达同样的意思所需的字符数往往只有三分之一左右。实测:`A[Payment received] --> B[Ship the order]` 渲染出的 viewBox 宽 204 像素,语义相同的 `A[已收到付款] --> B[发出商品]` 只有 156 像素。换行的像素宽度阈值是一样的,所以中文标签每一行能装下更多含义。结论是:中文流程图通常比英文原版更窄、更矮,把英文图翻译过来之后,往往可以把原先为了排版而做的拆分再合并回去。
高度每个节点约增加 105 像素,宽度几乎不变
自上而下的流程图,3 个节点的 viewBox 约为 122×382;到 40 个节点时是 131×4230——宽度只多了九像素,高度却涨了十一倍。长流程图会变成没有屏幕装得下的细长条,预览区的居中按钮就是为此准备的。如果图在竖直方向失控,改成 `flowchart LR` 只需一个词,往往能把宽高比减半。
标签是 HTML,这曾经让 PNG 导出失效
流程图的标签画在 SVG 的 `<foreignObject>` 里,内容是真正的 HTML。所以标签里能用 `<br>` 和简单的 Markdown。但这也意味着浏览器拒绝把该 SVG 画到 canvas 上,本站的 PNG 导出因此长期在无声地退回成 SVG 文件。现在导出会先用纯 SVG 文本标签重新渲染一遍,PNG 可以正常导出,代价是导出图中的字体排版与屏幕上略有差别。
主题只改颜色,从不改布局
同一张流程图用浅色和深色主题渲染,viewBox 完全一致。切换主题不会让图重排,也不会把标签挤出框外——所以深色模式下看着不对的地方,浅色模式下同样不对。
导出尺寸取自 viewBox,与屏幕无关
Mermaid 输出的是 `width="100%"` 且没有高度属性,屏幕上的大小取决于容器。导出时读取的是 viewBox,并按其二到三倍渲染,所以长流程图导出的 PNG 会比你眼前看到的大得多。缩放级别不影响导出结果。
什么时候该换一种图
如果图的重点是谁给谁发了什么、时间顺序比分支更重要,那么时序图会更清晰,而且随着规模增长依然清晰。一张把六个参与方写成节点名的流程图,其实是一张还没承认自己是时序图的时序图。
如果你描述的是一个对象可以处于哪些状态,而不是一个流程要走哪些步骤,那就用状态图。判断办法很简单:节点标签如果是“订单待处理”“订单已发货”这类带状态的名词,那是状态机;如果是“校验数据”“发送邮件”这类动词,那才是流程图。
而一旦超过大约四十个节点,老实说换哪种图都救不了。把它拆成几张共用一个入口的图,或者接受一个事实:你要描述的东西复杂到无法用一张图讲清楚——这本身也是有用的信息。
其他图类型
作者 Dominik Malsch · 最后更新: