首页
/ Mermaid 图表语法详解:声明式语法结构、Diagram 破坏字符规避与 Frontmatter/Directive 配置实战

Mermaid 图表语法详解:声明式语法结构、Diagram 破坏字符规避与 Frontmatter/Directive 配置实战

2026-09-06 13:31:44作者:袁立春Spencer

本文基于 Mermaid 仓库中的 Diagram Syntax 文档 展开,系统讲解 Mermaid 图表声明式语法的结构规则、会导致图表渲染失败的"破坏字符"及规避方案,并深入剖析 Frontmatter、Directive、initialize() 与主题配置四类定制手段的底层实现原理。读完本文,你将能够独立编写各类 Mermaid 图表、规避常见语法陷阱,并通过源码级理解正确运用 look(外观)与 layout(布局算法,含 ELK 参数)等配置项。

1. Mermaid 语法的整体定位

Mermaid 通过类似 Markdown 的纯文本语法生成流程图、时序图、ER 图等图表。其语法设计目标是"一天之内可学会",文档将 Mermaid 的整体能力划分为三大支柱:Syntax(语法)Deployment(部署)Configuration(配置),三者共同构成完整的 Mermaid 体系。

需要说明的是,docs/intro/syntax-reference.md 是一个自动生成的文档文件,其源文件位于 packages/mermaid/src/docs/intro/syntax-reference.md,文档头部明确标注 "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT"。这意味着仓库内语法文档与源码是同源维护的——修改语法文档应改源码侧的 .md 文件,构建流程会同步到 docs/ 目录。

各图表类型的完整语法示例可在 Mermaid Live Editor 中在线调试,仓库的 demos/ 目录也提供了 flowchart、sequence、er、gantt、state 等 30 余种图表类型的本地演示页面,适合作为语法练习场。

2. 语法结构:以图表类型声明开头

所有 Mermaid 图表定义都遵循统一的结构:第一行(或首个有效行)是图表类型声明(diagram type declaration),其后才是图内容定义。这个声明通知解析器应使用哪一类图表的解析规则。唯一的例外是位于图表代码最前面的 Frontmatter 配置

文档以 ER 图为例:erDiagram 声明告知解析器这是一张实体关系图,随后的每一行则是实体与关系的定义:

erDiagram
          CUSTOMER }|..|{ DELIVERY-ADDRESS : has
          CUSTOMER ||--o{ ORDER : places
          CUSTOMER ||--o{ INVOICE : "liable for"
          DELIVERY-ADDRESS ||--o{ ORDER : receives
          INVOICE ||--|{ ORDER : covers
          ORDER ||--|{ ORDER-ITEM : includes
          PRODUCT-CATEGORY ||--|{ PRODUCT : contains
          PRODUCT ||--o{ ORDER-ITEM : "ordered in"

各图表类型(flowchartsequenceDiagramganttclassDiagramerDiagram 等)的完整语法规则可在 docs/syntax/ 目录下按类型查阅,例如 flowchart.mdsequenceDiagram.md;入门示例见 docs/intro/getting-started.md

2.1 注释、未知词与静默失败的规则

  • 行注释%% 之后的内容会被忽略(解析前会经过 packages/mermaid/src/preprocess.tscleanupComments 的清理步骤);
  • 未知单词与拼写错误:会直接导致图表渲染失败(报错);
  • 配置参数错误:则会静默失败(silently fail)——这是文档特别强调的一个易错点,拼错配置项名不会报错,而是被默默丢弃,排障时需格外警惕。

2.2 源码佐证:图表代码的预处理流水线

从源码结构看,packages/mermaid/src/preprocess.ts 中的 preprocessDiagram 揭示了"声明式语法"背后的实际处理顺序:

  1. cleanupText:统一 CRLF 为 LF,并把 HTML 标签属性从双引号归一化为单引号(解析器对双引号会抛错);
  2. processFrontmatter:调用 extractFrontMatter 提取 YAML 元数据(见第 5 节);
  3. processDirectives:通过 utils.detectInit / utils.detectDirective 检测并剥离 %%{init}%% 等指令,同时识别 wrap 指令;
  4. cleanAndMerge:将 Frontmatter 配置与 Directive 配置按深度合并,再清理注释,最终产出 { code, title, config }

这一流水线解释了为什么 Frontmatter 和 Directive 可以在语法层面"抢先"影响渲染:它们都在正式解析图表声明之前被消费。

3. Diagram Breaking:会破坏图表的字词与符号

文档用一张持续更新的表格列出已知的"破坏字符"。这些词或符号数量不多,且通常只影响特定类型的图表,但一旦踩中就会让整个图表渲染中断:

破坏项 原因 解决方案
注释中的 %%{ }%% Directives 语法相似,会混淆渲染器 使用 %% 注释时避免在其中写花括号 {}
Flowchart / Sequence 中的 end 该关键字会让流程图与时序图解析中断 将含 "end" 的文本用引号包裹,例如 A["the end"]
Flowchart 中的"节点嵌套节点" Mermaid 对嵌套形状会解析混乱 用引号包裹防止解析错误

其中 end 是实际开发中最高频的踩坑点:在时序图里 end 是终止块的合法关键字,若在消息文本中裸写 "end" 就会提前截断交互块。docs/syntax/flowchart.md 的 "Special characters that break syntax" 一节有 flowchart 层面的进一步说明。

仓库的 e2e 测试为这类边界行为保留了真实语料,例如 e2e/diagrams/er-diagram/ 下覆盖特殊字符实体名、未转义标点的用例(should-render-entities-with-unescaped-attribute-names-or-types-containing-commas-or-periods.mmd),可用于对照验证破坏字符的处理行为。

4. 四类定制方式总览

文档指出,Configuration 是继 Deployment、Syntax 之后的第三大支柱,处理"Mermaid 在不同部署形态下如何被定制"。最常用的手段有四类,它们在功能上等价,但各自适合不同的部署场景

手段 适用场景 生效时机
Live Editor 的 Configuration 面板 在线编辑、即时预览 编辑期
initialize() 调用 API 或 <script> 标签引入时 初始化期,影响后续所有图表
Frontmatter 图表代码内部,随代码分发 该图表渲染前
Directives(%%{init}%% 图表代码内部 该图表渲染前
Theme Manipulation 通过 Directive 修改 theme 该图表渲染前

完整配置项参考见 docs/config/setup/README.mdinitialize() 的用法见 docs/intro/getting-started.md 的 "Calling the Mermaid JavaScript API" 一节。

5. Frontmatter:YAML 元数据

Frontmatter 指在图表代码开头附加 YAML 元数据,用于在渲染前重新配置该图。写法是用两条 --- 分隔线包住元数据定义,且开头的 --- 必须是该行唯一的字符

---
title: Frontmatter Example
displayMode: compact
config:
  theme: forest
gantt:
    useWidth: 400
    compact: true
---
gantt
    section Waffle
        Iron  : 1982, 3y
        House : 1986, 3y

规则要点(文档原文):

  • Frontmatter 使用 YAML 语法:缩进必须一致、键名大小写敏感
  • Mermaid 会静默忽略拼错的键,但格式不良的参数会直接打断图表——与第 2.1 节的"参数静默失败"规则相互印证;
  • 顶层支持 title(图表标题)、displayMode(目前用于 Gantt 的 compact 模式)、config(完整 Mermaid 配置对象),也可直接写 gantt: 等图表级配置段。

5.1 源码级解析逻辑

packages/mermaid/src/diagram-api/frontmatter.tsextractFrontMatter 实现了上述行为:

  • 匹配正则在 packages/mermaid/src/diagram-api/regexes.ts 中定义为 frontMatterRegex = /^([^\S\n\r]*)-{3}\s*[\n\r](https://gitcode.com/GitHub_Trending/me/mermaid/blob/0b41d039083e93336928cb034c019e0cd2eab5ab/.prettierignore?utm_source=gitcode_repo_files)[\n\r]\1-{3}\s*[\n\r]+/s——锚定在文件开头,并允许 --- 前存在一致缩进(捕获组 \1 在闭合同步用于去缩进,因为 js-yaml 拒绝 Tab 缩进的文档);
  • YAML 体使用 yaml.load(yamlBody, { schema: yaml.JSON_SCHEMA }) 解析,JSON Schema 是有意为之——注释中说明这是为了支持 config 字段的深度结构;
  • 解析后只白名单提取 displayModetitleconfig 三个显式支持的属性,其余键被静默丢弃(对应"静默忽略拼写错误"的行为);
  • 返回 { text: 去除 frontmatter 后的正文, metadata },供 preprocessDiagram 合并进配置。

packages/mermaid/src/preprocess.ts 中还有一个兼容性细节:若提供了 displayModeconfig.gantt 尚不存在,会补建 config.gantt 并写入 displayMode("Needs to be supported for legacy reasons"),解释了为什么 Frontmatter 里可以顶层写 displayMode: compact

e2e 测试 e2e/diagrams/conf-and-directives/ 中的 .mmd 语料(如 settings-from-frontmatter-nodes-should-be-grey.mmdsettings-from-initialize-nodes-should-be-green.mmd)验证了 Frontmatter 与 initialize() 两种配置来源的优先级与渲染效果,可作为回归参考。

6. Directives:%%{init}%% 指令

Directives 允许在图表代码内部、紧邻定义处进行有限的重配置,可改变字体、颜色等外观属性。写法是把指令放在 %%{ }%% 内,置于图表定义之前或之后均可:

%%{init: {'theme':'forest', 'flowchart': {'curve':'bump'}}}%%
flowchart LR
  A --> B

从源码结构看,Directives 的检测与剥离发生在 packages/mermaid/src/utils.tsdetectInit / detectDirective 中:detectInit 匹配 initinitialize 关键字后的 JSON 负载,解析出的配置对象与 Frontmatter 的 configcleanAndMerge 中深度合并;removeDirectives 则负责把指令行从正文中剔除,使其不参与图表解析。合并优先级行为可用 packages/mermaid/src/config.spec.ts 中的用例对照(例如 initConfig 与 directive 同时存在时 layoutfontSize 的覆盖关系)。

主题操控(Theme Manipulation) 就是 Directive 的一个特化应用:theme 是 Mermaid 配置中的取值项,决定图表配色方案,完整主题体系见 docs/config/theming.md。配置类型定义 packages/mermaid/src/config.type.tsMermaidConfig.theme 的可选值包括 defaultbasedarkforestneutralneoneo-darkreduxredux-darkredux-colorredux-dark-colornull,还可配合 themeVariables / themeCSS 进一步覆盖。

7. Layout 与 Look:布局算法和外观风格

Mermaid 重构了图表渲染方式后,新增了"选择布局(layout)与外观(look)"的能力,目前支持 flowchart 与 state 图,并计划扩展到所有图表类型。

7.1 选择 Look(外观)

  • Hand-Drawn Look(手绘风):为图表带来手绘草图质感,适合非正式场景或想增添个性时;
  • Classic Look(经典风):保持多数用户熟悉的传统 Mermaid 外观,适合跨项目保持一致性。

在图表元数据(Frontmatter)的 config.look 中指定:

---
config:
  look: handDrawn
  theme: neutral
---
flowchart LR
  A[Start] --> B{Decision}
  B -->|Yes| C[Continue]
  B -->|No| D[Stop]

配置类型 packages/mermaid/src/config.type.tsMermaidConfig.look 的实际取值为 'classic' | 'handDrawn' | 'neo'(比文档列举的两种多了一个 neo),另有配套的 handDrawnSeed 参数:它定义手绘风的随机种子,默认为 0(即每次随机),固定种子可获得确定性渲染结果——这对截图对比类自动化测试尤为重要(仓库 e2e 用例 should-render-edges-at-correct-length.mmd 所在 architecture 用例即带 seed 覆盖的确定性布局验证)。

各图表渲染器如何消费该值,可从源码结构看:packages/mermaid/src/diagrams/flowchart/flowDb.tspackages/mermaid/src/diagrams/class/classDb.tspackages/mermaid/src/diagrams/er/erDb.ts 等都在读取 config.look 后传入各自的渲染路径。

7.2 选择布局算法(Layout)

config.layout 决定节点与边在页面上的排布方式,目前两种:

  • Dagre(默认):Mermaid 长期使用的经典布局算法,简洁性与清晰度平衡较好,适合大多数图表;
  • ELK(Eclipse Layout Kernel):面向大型、复杂图表的高级布局,排列更优、可减少节点重叠并提升可读性。ELK 并非开箱即用,在站点/应用集成 Mermaid 时需要额外引入(对应仓库子包 packages/mermaid-layout-elk/),并通过 initialize() 调用时注册。

在 Frontmatter 中指定布局的示例:

---
config:
  layout: elk
  look: handDrawn
  theme: dark
---
flowchart TB
  A[Start] --> B{Decision}
  B -->|Yes| C[Continue]
  B -->|No| D[Stop]

其中 layout: elk 一行即切换到 ELK 布局,同时叠加手绘外观与 dark 主题。若想回到默认组合:

---
config:
  layout: dagre
  look: classic
  theme: default
---
flowchart LR
A[Start] --> B{Choose Path}
B -->|Option 1| C[Path 1]
B -->|Option 2| D[Path 2]

7.3 精细化定制 ELK 布局

使用 ELK 时可进一步调整节点排布与边合并行为,全部参数均可写入 Frontmatter 的 config.elk(对应类型定义在 packages/mermaid/src/config.type.tsMermaidConfig.elk):

参数 取值 说明
mergeEdges true / false 让并行边共享路径,图更紧凑但可能降低可读性
nodePlacementStrategy SIMPLENETWORK_SIMPLEXLINEAR_SEGMENTSBRANDES_KOEPF(默认) 控制节点摆放策略
nodePlacementAlignment NONE(默认,选高度最小的对齐方式)、LEFTUPLEFTDOWNRIGHTUPRIGHTDOWNBALANCED 配合 Brandes-Koepf 策略的对齐方向

文档给出的完整示例:

---
config:
  layout: elk
  elk:
    mergeEdges: true
    nodePlacementStrategy: LINEAR_SEGMENTS
    nodePlacementAlignment: NONE
---
flowchart LR
  A[Start] --> B{Choose Path}
  B -->|Option 1| C[Path 1]
  B -->|Option 2| D[Path 2]

从源码结构看,ELK 布局的具体实现位于独立的 packages/mermaid-layout-elk/ 包(src 下 8 个 TypeScript 模块),主包通过 config.layout 的值分发到对应布局适配器;e2e 目录中 e2e/diagrams/flowchart/elk/(56 个用例)与 e2e/diagrams/class-diagram/elk/(60 个用例)保存了 ELK 布局下的真实图表语料,可用于观察上述参数在复杂图上的实际效果差异。

8. 小结与实操建议

  • 写图表:永远以图表类型声明开头;含 end{} 等敏感词的文本一律加引号包裹;注释中避免 %%{ }%% 形态的花括号组合;
  • 定行为:全局定制用 initialize()docs/intro/getting-started.md),单图定制优先 Frontmatter(结构化、支持完整 config 树),快速调主题用 Directive(docs/config/directives.md);
  • 避静默坑:拼错的 Frontmatter 键与拼错的配置参数都不会报错,排障时应对照 packages/mermaid/src/config.type.tsMermaidConfig 类型定义逐一核对键名与取值;
  • 选布局:中小图表用默认 dagre;大型或嵌套复杂图切 layout: elk 并按需调 mergeEdgesnodePlacement* 参数,前提是集成侧已注册 ELK 布局包(packages/mermaid-layout-elk/)。
登录后查看全文
热门项目推荐
相关项目推荐