免费 · 无需注册 · 支持 .mmd 文件

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 --> Stop
在编辑器中打开

4. 用子图按归属分组

子图会给相关节点画一个框。最有价值的分组方式往往不是按流程阶段,而是按归属——哪个团队或哪个服务负责哪一段,这样交接点就显现出来了。

flowchart TD
    subgraph client [浏览器]
        UI[用户提交表单]
    end
    subgraph api [订单服务]
        Validate[校验请求数据]
        Persist[写入订单记录]
    end
    subgraph async [后台任务]
        Email[发送确认邮件]
        Invoice[生成发票]
    end
    UI --> Validate
    Validate --> Persist
    Persist --> Email
    Persist --> Invoice
在编辑器中打开

5. 有明确出口的重试循环

流程图处理环路毫无问题,而重试循环正是它发挥价值的地方——图能一眼看出这个循环到底有没有出口。

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[开始] --> end
正确写法
flowchart TD
    Start[开始] --> End[已结束]

你会看到

在你命名节点的那一行报 Parse error

原因

节点 ID 里带了空格。ID 是箭头前面的那个标记,空格会把它截断,解析器就剩下一个无处安放的词。

解决办法

用单个词作 ID,把可读文字放进标签。

错误写法
flowchart TD
    auth service --> user db
正确写法
flowchart TD
    auth[认证服务] --> db[(用户数据库)]

你会看到

在两条竖线之间的边标签处报 Parse error

原因

边标签里出现了括号。`|…|` 和节点标签的限制一样——括号在那里仍是语法,不是文本。

解决办法

把边标签也加上引号。

错误写法
flowchart TD
    A -->|是 (总是)| B
正确写法
flowchart TD
    A -->|"是 (总是)"| B

你会看到

Lexical error on line 1. Unrecognized text.

原因

方向写错了。流程图只接受 TB、TD、BT、LR、RL,写错会在词法阶段就失败,此时还没读到任何节点——所以报错指向第 1 行而不是你真正写错的地方。

解决办法

用这五个之一。TD 和 LR 基本够用。

错误写法
flowchart TOPDOWN
    A --> B
正确写法
flowchart 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 · 最后更新:

打开编辑器 →