最近技术社区里关于 open code、OSS 协作与 AI 编码工具的讨论明显多了起来。与之相伴的一个小话题很有意思:有开发者用“艺术自由”来形容某些开放式 OSS 创作集体产出的 Mermaid 图——同一套文档体系里,每张流程图风格都不一样,有的节点拥挤,有的配色刺眼,有的方向混乱。Dex Horthy 的调侃也让“Mermaid 图渲染风格”这个细节进入了更多人的视野。
相比追着这句调侃本身讨论,更值得做的是把问题拆开,看明白 Mermaid 图为什么会出现风格不一致、渲染结果受哪些因素控制,以及在一个多人和自动生成内容的环境里,如何让图表风格回归统一。本文会从概念、语法、渲染工具链和协作规范四个层面展开,适合正在使用 Mermaid 写技术文档、也在尝试 AI 辅助编码的开发者阅读。
1. 一句关于“Mermaid 图风格”的吐槽,背后藏着什么问题
Mermaid 是一种使用文本描述图表的语言。开发者通常把它写在 Markdown 文档的代码块中,由渲染器转换成流程图、时序图、类图等。相比传统的可视化拖拽画图工具,Mermaid 的最大优势是“图即是代码”,可以进入版本管理、支持 Diff 对比、方便在代码评审中被检查和修改。
开放式 OSS 创作团队之所以喜欢 Mermaid,正是因为它适合多人协作:任何成员都可以在文档里修改节点和连线,不需要打开专业绘图软件,也能通过 Pull Request 提交图表变更。而 AI 编码工具进一步拉低了生成门槛,输入需求后就能返回一段 Mermaid 源码,放进文档可能就直接渲染出图。
但问题也随之而来。当同一个仓库里的 Mermaid 图来自不同成员、不同工具甚至不同 AI 会话时,会出现明显的风格割裂:
- 有人习惯纵向布局,有人使用横向布局。
- 有人使用 Mermaid Live Editor 导出 PNG,有人直接让网页端 CDN 渲染。
- 有人使用默认主题,有人手工调了节点背景色,却只在自己的编辑器里生效。
- AI 生成的图经常结构复杂、说明性文字冗长,稍不注意就会渲染成一张横向撑满屏幕、节点相互挤压的大图。
这些都属于图表“渲染风格”问题。Dex Horthy 调侃的其实并不是 Mermaid 本身,而是“自主化协作”场景下缺少统一约束,导致代码与视觉呈现双双失控。本文从技术角度把这条线捋清楚,再给出可落地的工程方案。
2. Open Code 与 OSS 创作集体中的 Mermaid:先厘清几个相关概念
2.1 Open Code 与 OSS 创作集体可能指什么
首先要说明,单看“Open Code”,不同语境下含义差别很大。在本文讨论的社区语境里,它往往和“开源、开放协作、AI 辅助编码”绑定在一起,描述的是开发者把代码、文档、Prompt 工作流放出来共享,并允许他人参与共创的一种方式。
OSS 创作集体则更像是“一群人基于开放源码的方式共同产出内容或软件”。它不一定指某个固定组织,也可以是一种协作模式:有人维护主仓库,有人提交 issue,有人改进文档,AI 工具则负责生成初稿、补齐注释、批量画图。
这三组关键词结合在一起,说明现在开源协作中已经出现了一条很典型的链路:社区成员或 AI 工具先产出 Mermaid 源码,随后由渲染器生成图片,最终呈现给用户。Mermaid 图风格不一致的问题,就是这条链路里缺少中间约束层的体现。
2.2 Mermaid 到底是什么
Mermaid 的官方定位是基于 JavaScript 的图表绘制工具,开发者使用类似 Markdown 的文本语法定义图表。一个最简单的流程图如下:
flowchart LR A[需求文档] --> B[Mermaid 源码] B --> C[渲染成图]这段文本被 Mermaid 解析器处理后,会生成一个横向排列的流程图。Mermaid 支持的类型远比流程图丰富,包括:
- flowchart / graph:流程图。
- sequenceDiagram:时序图。
- classDiagram:类图。
- stateDiagram-v2:状态图。
- erDiagram:实体关系图。
- pie:饼图。
- gitGraph:Git 分支图。
对非专业绘图人员来说,掌握 flowchart、sequenceDiagram 和 classDiagram 已经能覆盖绝大多数技术文档场景。
2.3 图表“渲染风格”具体包含什么
“渲染风格”并不只是颜色是否好看,它其实由多个渲染参数共同决定:
- 布局方向:flowchart 是从上到下,还是从左到右。
- 主题:default、neutral、dark、forest、base,不同主题会改变配色和连线风格。
- 节点样式:背景色、边框色、圆角、字体颜色、线条宽度。
- 连线样式:是否带箭头、是否使用曲线、是否有文字标签。
- 画布尺寸:输出 SVG 或 PNG 的宽高、缩放比例。
- 字体:不同操作系统和浏览器对中文、英文、代码字体的渲染结果不同。
理解这些参数,是统一多人协作产出物的第一步。
3. 为什么同一段 Mermaid 源码,在不同环境渲染出来不一样
很多开发者第一次遇到 Mermaid 风格问题时,会觉得很困惑:明明源码一模一样,为什么本地预览、Mermaid Live Editor、GitHub 渲染和命令行导出的效果各不相同?原因主要有四层。
3.1 解析器或渲染器版本不同
Mermaid 版本迭代很快。旧版本对 classDef、subgraph 的解析规则,与新版本可能并不完全兼容。当你的本地 Markdown 编辑器内嵌的是 Mermaid 9.x,而项目文档基于 Mermaid 11.x 编写时,同一段源码有可能出现节点布局差异、classDef 样式不生效、子图文字位置变化等问题。
这类问题最隐蔽,因为前端工具通常不会主动提示 Mermaid 内核版本。排查时,要把“Mermaid 版本一致”当作第一条检查项。
3.2 渲染容器或平台主题不同
不同平台会主动套用自己的主题。举例来说:
| 渲染端 | 主要特点 |
|---|---|
| Mermaid Live Editor | 在线调试方便,可在 UI 中切换 default/dark/neutral/forest 主题 |
| GitHub / GitLab | 内置渲染器,风格跟随站点的亮色或暗色模式 |
| Typora / VS Code 等本地工具 | 跟随编辑器主题,自定义变量设置方式差别较大 |
| Mermaid CLI | 命令行控制,可控主题、背景色、缩放比例 |
也就是说,同一段 Mermaid 源码在 Mermaid Live Editor 里显示为白底黑框,到了某个暗色主题的文档站点里就可能自动变为深色背景。设计文档的人如果没有约定“最终展示以哪套渲染方式为准”,风格就会非常飘。
3.3 输出尺寸、字体与画布参数不同
直接截图和通过 Mermaid CLI 导出 SVG,两者对画布尺寸的处理方式完全不同。常见差异包括:
- 通过网页截图导出的图片,宽高取决于浏览器视口,容易裁切。
- PNG 默认没有透明背景,嵌入暗色文档会出现白底方块。
- 同一台机器缺少中文字体时,导出 PNG 中的中文可能变成“方框”。
- SVG 默认宽高可能和文档排版宽度不匹配,造成图片过大或过小。
这些“看起来像图片问题”的现象,其实都和渲染风格强相关。
3.4 协作者“手写风格”不稳定
多人协作还有一个隐藏因素:每个人写 Mermaid 源码的习惯不同。
- 有人习惯
graph TD,有人喜欢flowchart LR。 - 有人把长文本作为节点标签,导致节点宽度爆炸。
- 有人为每个节点都写 style,颜色越改越多,最终完全失去统一视觉。
- AI 生成时如果不指定风格,更会随机输出不同的布局方向、描述措辞和节点命名。
从工程视角看,第 4 点比版本差异更容易处理,因为它可以通过规范和模板约束。第 3 点则需要引入命令行工具和 CI 进行固定。
4. Mermaid 源码与风格控制的几个关键语法点
在进入统一风格实操之前,有必要先理解 Mermaid 源码里哪些位置会影响最终渲染效果。
4.1 布局方向由第一行决定
graph是 Mermaid 较早的流程图写法,flowchart是改进后的版本,二者常用语法大体一致。第一行声明的方向决定了整张图的流向:
flowchart TB A[准备数据] --> B[编写 Mermaid] B --> C[渲染验证]TB表示从上到下,LR表示从左到右。编写多人共享的图时,要在模板里固定方向,否则同样的逻辑内容会因为TB和LR的切换产生截然不同的排版观感。
4.2 subgraph 与节点文本怎么组织会影响可读性
当节点数量超过 7 到 8 个,继续把所有节点平铺在一条链上,视觉效果会大幅下降。此时应该用subgraph把相关的节点圈成组:
flowchart TB subgraph inputGroup["输入层"] A[原始需求] B[代码文件] end subgraph processGroup["处理层"] C[解析上下文] D[生成 Mermaid 源码] end subgraph outputGroup["输出层"] E[渲染并导出] F[文档展示] end A --> C B --> C C --> D D --> E E --> F每个subgraph可以设置一个分组标题,如输入层。在多人协作中,如果规定“超过 6 个主节点必须分组”,图的可读性会稳定很多。
4.3 classDef 是统一节点配色的核心语法
很多开发者会直接用style A fill:#f00的方式修改单个节点。但在大图中,这种写法会导致每新增一个节点都要复制一条 style 语句,非常难维护。
更好的方式是使用classDef定义“样式类”,再把样式类附加到节点上:
flowchart LR A[开始]:::startNode --> B{检查环境}:::checkNode B -->|通过| C[执行任务]:::taskNode B -->|失败| D[输出错误]:::errorNode classDef startNode fill:#EAF2FB,stroke:#2F6F9F,color:#222222,stroke-width:1.5px; classDef checkNode fill:#FFF4CE,stroke:#D29E00,color:#222222; classDef taskNode fill:#FFFFFF,stroke:#7A7A7A,color:#222222; classDef errorNode fill:#FDE7E9,stroke:#C0392B,color:#222222;当团队约定好几种固定样式类后,其他成员画图时只需要引用:::startNode、:::errorNode,颜色自然统一。
4.4 init 指令可以集中控制主题变量
Mermaid 允许在源码开头使用%%{init: {...}}%%指令覆盖默认主题配置。例如:
%%{init: { "theme": "base", "themeVariables": { "primaryColor": "#EAF2FB", "lineColor": "#2F6F9F", "textColor": "#222222" } }}%% flowchart LR A[入口] --> B[处理] B --> C[出口]要注意的是,init 指令虽然强大,但不是所有渲染平台都会完全执行或允许执行。部分在线平台出于安全考虑会对脚本类配置做限制。因此,团队需要提前验证“最终发布平台是否支持 init 指令”,不能简单依赖它。
4.5 节点文本与特殊字符处理
Mermaid 对节点文本的要求比较宽松,但当文本中包含括号、引号、HTML 标签时,必须放在节点形状内部或使用引号包裹。例如:
flowchart LR A["请求参数(JSON)"] --> B["响应状态: OK"]在自动生成场景中,AI 很可能输出包含大量标点和换行的节点文本,导致渲染异常。规范中应当约定:节点标题尽量使用短名词,长说明文字交给 subgraph 分组或图下方的 Markdown 正文承载。
5. 实操:用 Mermaid CLI 统一导出一套风格一致的图
如果团队的目标只是“在文档里插入 Mermaid 代码块,让平台自动渲染”,那风格的统一度取决于平台。若希望图在文档站、PPT、公众号或离线场景中使用,则应当引入命令行工具,让图片在 CI 中按统一参数生成。
5.1 为什么选择 CLI 而不是人工截图
人工截图存在几个明显的工程问题:
- 浏览器窗口尺寸不同,导出图片宽高不稳定。
- 截图无法固定背景色,png 默认可能是白底。
- 每次修改 Mermaid 源码后都重新截图,容易出现源码与图片不一致。
- 无法在 Pull Request 流水线中自动校验图片是否过期。
使用 Mermaid CLI 的最大价值,是让“生成图片”变成一个可重复执行的命令。任何人拉取代码后执行一次渲染,都能得到完全相同的图片文件。
5.2 安装 @mermaid-js/mermaid-cli
Mermaid CLI 是一个基于 Node.js 和 Puppeteer 的工具。安装前需要确认环境中有 Node.js,建议使用 Node.js 18 或 20 的 LTS 版本。项目内安装方式如下:
npm init -y npm install --save-dev @mermaid-js/mermaid-cli安装过程会拉取 Puppeteer 对应的 Chromium。如果安装缓慢或失败,通常是网络策略问题,可以检查 npm 镜像配置。安装完成后,通过 npx 调用:
npx mmdc --version5.3 渲染单个 Mermaid 文件
把 Mermaid 源码保存到.mmd文件中,然后执行:
npx mmdc -i docs/diagrams/workflow.mmd -o docs/images/workflow.svg --theme base -b transparent参数含义如下:
-i:输入文件路径。-o:输出文件路径。--theme:指定主题。-b:指定图片背景色,transparent表示透明背景。
如果希望导出 PNG,可以把扩展名改成.png,并增加-s缩放比例:
npx mmdc -i docs/diagrams/workflow.mmd -o docs/images/workflow.png -s 2 -b white这里-s 2表示按 2 倍分辨率导出,适合文档站需要高清图片的场景。
5.4 在服务器环境中使用 puppeteer 配置
很多 Linux 服务器没有图形界面,Chrome 运行时会缺少必要的系统依赖。常见的解决方式是提供 puppeteer 配置,让 Chromium 以 no-sandbox 方式运行。
新建文件puppeteer-config.json:
{ "args": [ "--no-sandbox", "--disable-setuid-sandbox" ] }渲染时通过-p指定配置文件:
npx mmdc -p puppeteer-config.json -i docs/diagrams/workflow.mmd -o docs/images/workflow.svg注意:--no-sandbox会降低浏览器进程隔离能力,在 CI 容器或受限环境中使用时,应先确认安全策略允许。
5.5 批量渲染脚本
项目中的图不只一张,建议编写脚本遍历目录中的全部.mmd文件。新建scripts/render-diagrams.sh:
#!/usr/bin/env bash set -euo pipefail INPUT_DIR="${1:-docs/diagrams}" OUTPUT_DIR="${2:-docs/images}" mkdir -p "$OUTPUT_DIR" for file in "$INPUT_DIR"/*.mmd; do [ -e "$file" ] || continue name="$(basename "$file" .mmd)" echo "Rendering ${name} ..." npx mmdc -p puppeteer-config.json \ -i "$file" \ -o "$OUTPUT_DIR/${name}.svg" \ --theme base \ -b transparent done给脚本增加执行权限后运行:
chmod +x scripts/render-diagrams.sh ./scripts/render-diagrams.sh在package.json中加入脚本命令,方便团队统一调用:
{ "name": "docs-render", "scripts": { "diagrams": "bash scripts/render-diagrams.sh" }, "devDependencies": { "@mermaid-js/mermaid-cli": "^11.0.0" } }之后项目成员只需执行:
npm run diagrams即可在本地重新生成全部文档图片。
5.6 结果验证
渲染完成后,检查docs/images目录下是否生成了对应的 SVG 文件。推荐在浏览器中打开 SVG,重点确认:
- 中文是否正常显示。
- 节点之间是否有重叠。
- 每一层的宽度是否合理。
- 深色模式下透明背景是否正确。
如果发现中文乱码,可在服务器安装中文字体。以 Debian/Ubuntu 为例:
apt-get update apt-get install -y fonts-noto-cjk安装后重新执行渲染命令即可。
6. 多人/自动生成协作中如何把 Mermaid 风格“关进笼子”
仅有命令行渲染还不够。一个活跃的 OSS 仓库中,新增图表的人可能完全没有接触过渲染脚本,因此必须在仓库层建立一套明确约定。
6.1 约定目录与命名规范
建议在文档仓库中固定 Mermaid 源码与图片产物的目录:
docs/ diagrams/ # 存放 *.mmd 源文件 images/ # 存放渲染后的图片命名建议使用英文小写短横线。比如:
docs/diagrams/ci-workflow.mmd docs/images/ci-workflow.svg源代码与图片分开管理,可以避免 Pull Request Diff 把源码和二进制图片混成一团。
6.2 提供一个统一的 Mermaid 模板
在docs/diagrams/_template.mmd中放一个基础模板,让新成员直接复制使用:
%%{init: { "theme": "base", "themeVariables": { "fontFamily": "Noto Sans CJK SC, PingFang SC, Microsoft YaHei", "primaryColor": "#EAF2FB", "primaryBorderColor": "#2F6F9F", "lineColor": "#5A5A5A" } }}%% flowchart TB subgraph groupA["模块 A"] A1[开始] A2[处理] end A1 --> A2模板统一了方向、中文字体、主题变量和分组风格。成员复制后只需要修改节点内容,视觉结果天然保持一致。
6.3 将渲染纳入 CI
如果项目托管在 GitHub,可以通过 GitHub Actions 在 Pull Request 阶段自动渲染图片,并检查图片是否更新。
在.github/workflows/render-diagrams.yml中写入:
name: render-diagrams on: pull_request: paths: - "docs/diagrams/**" jobs: render: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Node uses: actions/setup-node@v4 with: node-version: 20 - name: Install dependencies run: npm ci - name: Render diagrams run: npm run diagrams - name: Verify no uncommitted images run: | git diff --exit-code docs/images当贡献者只提交了.mmd文件、忘记更新图片时,CI 会在最后一步失败,提醒他重新执行npm run diagrams并提交图片。
如果是内部 GitLab,也可以在.gitlab-ci.yml中实现相同逻辑,核心思路一致:先渲染,再用git diff检查产物是否有变化。
6.4 面向 AI 编码工具的生成约束
标题中提到的 Open Code / autonomous OSS 场景,绕不开“AI 自动生成 Mermaid 源码”。想让 AI 生成的内容符合团队风格,不能只靠事后修改,而是要在 Prompt 阶段给足约束。下面这段提示词可以作为参考模板:
请生成一段 Mermaid flowchart 源码,要求如下: 1. 使用 flowchart TB,不用 graph TD; 2. 节点文本使用中文,语义精炼,不超过 15 个字; 3. 主流程节点数量不超过 6 个; 4. 超过 6 个节点时,使用 subgraph 按模块分组; 5. 不要直接在代码中散落 style 语句,用 classDef 定义公共样式; 6. 输出内容只包含 Mermaid 源码,不要额外解释。对于更成熟的项目,可以把这份约束写入仓库根目录的AI_GUIDE.md或CONTRIBUTING.md,让所有使用 AI 工具的协作者看到同样的规则。
6.5 把代码评审变成图评审
在 Pull Request 评审时,很多人只 Diff Mermaid 源码,没有打开渲染后的图片。对于视觉改动,这个习惯需要调整。
建议在 PR 描述模板中加入:
- 本次变更对应的 Mermaid 源码文件。
- 变更前图片链接。
- 变更后图片链接。
- 变更影响范围:新增模块、调整流程、修改文案或仅调整样式。
这一步看起来像流程要求,实际能避免大量“代码没问题,但渲染后一团糟”的返工。
7. 常见问题与排查思路
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 同一份 Mermaid 源码在本地和 CI 中渲染结果不同 | Mermaid 版本不一致或渲染器主题不同 | 锁定 package 版本,使用 Mermaid CLI 统一渲染 |
| 导出 PNG 后中文变成方块 | 运行环境缺少中文字体 | 安装 fonts-noto-cjk 或其他中文字体 |
| 图太宽,在文档中挤压排版 | 主流程节点过多,或使用了横向布局而内容超长 | 增加 subgraph 分组,拆分为多个小图 |
| 节点样式在某个平台不生效 | classDef 语法不兼容或平台不支持该配置 | 在 Mermaid Live Editor 中验证语法,并固定平台 |
| 使用 init 指令后页面不渲染 | 平台出于安全限制禁用了部分配置 | 移除 init,改用 CLI 导出图片 |
| 图片和源码不一致 | 修改 .mmd 后忘记重新导出 | 在 CI 中加入渲染检查步骤 |
| AI 生成的图经常出现多余说明或复杂结构 | Prompt 中缺少风格约束 | 使用标准模板并在 Prompt 中限定节点数量与语法 |
遇到无法解决的渲染问题时,推荐把一段最小可复现的 Mermaid 源码粘贴到 Mermaid Live Editor,切换不同的 Mermaid 版本和主题做对照实验。这个方法可以快速定位是“源码写法问题”还是“渲染环境问题”。
8. 最佳实践:让 Mermaid 图成为文档里的稳定构件
经过上面的流程,团队基本可以实现 Mermaid 图的“可重复构建”。在此基础上,有几点工程建议值得直接落地:
第一,把 Mermaid 版本放进依赖锁文件。团队文档应用和 CLI 工具应使用同一条依赖链,避免应用自动升级 Mermaid 后,旧图片批量出现样式回归。
第二,让“源码目录”和“图片目录”一一对应。源文件与产物遵循相同命名规则,让人看到workflow.mmd就能推测出对应workflow.svg,降低维护成本。
第三,把模板作为仓库中的一等公民。模板文件不仅要放在docs/diagrams/下,还要在 README 中说明“新图请从模板复制”,让新贡献者一开始就走正确路径。
第四,给 AI 生成内容设置验收红线。当前 AI 编码工具生成 Mermaid 图的速度很快,但生成结果的稳定性不足以直接信任。至少要检查布局方向、节点结构、classDef 是否有效,并在本地完成渲染预览后再合入。
第五,重视图片在文档站点中的展示容器。即使 SVG 导出正确,如果页面 CSS 设置了max-width,不同宽高比的图仍可能出现显示差异。规范中应约定统一的图片展示宽度和主题色变量。
从社区调侃到工程落地,Mermaid 图风格不一致不是一件小问题。它影响文档审美,也影响协作效率。通过锁定版本、固定命令、提供模板、写入 CI 和约束 AI 生成行为,一套看起来“有人味”的图渲染风格,完全可以变回稳定的标准化产物。这也是开放式 OSS 协作走向成熟时,非常值得补上的一环。