
我在VSCode里写了快三年Markdown项目方案、技术笔记、复盘文档基本全在编辑器里完成。Markdown写文档确实舒服但有一件事在过去一直很尴尬画流程图、时序图、ER图的时候很多人第一反应是切到在线工具画完再截图贴进来或者装一套带界面的重型插件。后来我找到 Markdown Preview Mermaid Support 这个插件VSCode的Markdown预览终于能直接渲染Mermaid代码流程图、时序图、类图原地生成不用再切来切去。可事情并没到此结束——等图表里的节点数量上到二三十个Mermaid默认的配色几乎没法看密密麻麻全是同一种蓝条件分支、角色区分、状态变化全都压在一张图上。直到我把classDef这套布局样式语法真正吃透才觉得Mermaid算是被我用明白了。这篇文章就把插件安装、classDef语法和应用经验一次讲完。1. 装好插件只是第一步Markdown Preview Mermaid Support的使用前提1.1 这个插件到底干了什么Markdown Preview Mermaid Support是VSCode扩展市场里的一个Markdown预览增强插件扩展ID是bierner.markdown-mermaid作者是Matt Bierner。它做的事情听起来很简单让VSCode内置的Markdown预览能识别并渲染Mermaid代码块。你在Markdown里写一段以mermaid开头结尾的代码插件会把它交给Mermaid.js渲染成SVG然后显示在预览面板里。这个交互是即时的改完图、保存文档、切回预览几秒钟内就能看到最新结果基本不用等。理解它的原理对后面排坑很重要。VSCode的Markdown预览本身基于markdown-it渲染管线并且官方预留了扩展点允许第三方插件往管线里注入自定义转换器。Markdown Preview Mermaid Support做的就是这件事把mermaid代码块转成一个div classmermaid容器再用Mermaid.js在预览页面里执行渲染。所以它不需要额外配置就能生效——你想改配置反而没多少可改的。知道了这层关系你就明白遇到预览没反应时八成不是插件坏了而是语言标签写错或者被别的扩展抢先处理了。1.2 五分钟跑通第一个图表安装过程没什么花样打开VSCode左侧扩展面板或者按CtrlShiftX。搜索栏输入Markdown Preview Mermaid Support注意拼写别少词。点击安装完成。新建一个.md文件输入下面的最小示例。按CtrlShiftV打开Markdown预览或者按CtrlK V在侧边打开预览。等一个最小示例代码## 订单流程 下面是一个最基础的流程图 mermaid flowchart LR A[开始] -- B{是否下单} B --|是| C[生成订单] B --|否| D[结束] 如果一切正常预览面板里会看到两个矩形、一个菱形、四条箭头命令行窗口不会报错。这里最容易犯的错是代码块的语言标签不写mermaid而是写了mmmermaid、mermaidjs之类那插件就识别不到预览会原样显示成代码块文本。另外Mermaid本身对语法错误非常敏感如果你把--写成-或括号没配对预览里会直接出现一行红色报错信息而不是图。记住这个特征看到报错提示先怀疑Mermaid语法再怀疑插件本身。1.3 同类插件怎么选避免装了打架扩展市场里名字相近的插件不少最容易被拿来对比的是Markdown Preview Enhanced。两者的定位差异很明显插件定位优点需要留意的地方Markdown Preview Mermaid Support轻量单一功能对VSCode内置预览改动小安装即用可配置项很少Markdown Preview EnhancedMarkdown全家桶导出、目录、数学公式等功能很全自带Mermaid渲染但与本文主角逻辑可能冲突我的建议是如果你只想解决Mermaid图表在Markdown里预览这一个问题装轻量的就好如果你本来就重度依赖Markdown Preview Enhanced的导出、目录、自定义CSS这些能力那就别再叠装。两个都能渲染Mermaid的插件同时开着预览时可能出现图表被渲染两次或者一个占位符被另一个覆盖的情况。排查这类问题最快的方法是把其中一个禁用、重新加载VSCode窗口看一下预览是否恢复。另外再提醒一句任何改动了markdown-it渲染管线的扩展都有可能在某个版本更新后互相踩脚遇到预览异常逐个禁用扩展是最原始的排查手段也是最有效的。2. classDef是什么以及它为什么值得单独学2.1 没有classDef时大图表的真实状态Mermaid默认主题下流程图里几乎所有节点共享同一套蓝色系。画一个只有五六个节点的小图当然没问题但等节点上了二十个连带有回退、多分支的时候整张图就变成一大片蓝色块加箭头线眼睛很难定位哪个是开始、哪个是判断、哪个是异常流程。很多人因为这个弃用Mermaid画大图说它图一多就乱问题其实不在Mermaid而在缺少一套有效的样式控制手段。我印象很深的一次是画一个包含库存、支付、物流、售后四个子流程的订单总览图总共三十几个节点。用默认样式画完自己都懒得再看第二眼。后来我把几种关键节点分别用颜色区分开再用虚线边框标出数据存储类节点整张图的可读性立刻上了一个台阶。这就是classDef最大的价值让颜色和样式成为一种视觉语言而不是单纯装饰。2.2 classDef的定位给节点贴CSS类写前端的同学对CSS类这个概念应该很熟。classDef做的事情就是把CSS类的思路搬进Mermaid你先定义一个样式类指定填充色、边框颜色、边框粗细这些属性然后把一个或多个节点归属到这个类。节点会立即套用对应样式类和节点之间是松耦合的关系改样式只改定义处不用去翻几十个节点。Mermaid本身也提供了逐节点的style语句比如style A fill:#4CAF50,stroke:#333这种写法对一两张小图很直接但在大图里逐节点维护就是给自己挖坑。改一个颜色要改十几个style改着改着就漏了一个。classDef把样式集中管理配色调整只动一行维护成本完全可控。如果你之前画图从没做过样式规划第一次用classDef处理一张三十个节点的图你会明显感受到图突然变干净了。2.3 一个典型需求颜色即角色举个实际场景画一个登录流程里面有输入账号、校验格式、查缓存、查数据库、返回成功、返回错误这么几条路径。全部默认蓝时用户根本看不出哪条是主流程哪条是异常分支。用classDef定义四个类primary关键路径节点用蓝色。branch判断分支节点用橙色。data数据库/缓存的读写节点用灰色虚线边框。error异常节点用红色。然后把对应的节点挂到类上。这时候整张图的阅读逻辑就是颜色即角色扫一眼就能抓住重点。看的人也舒服改的人也方便。这也是classDef最核心的使用思路——先想清楚这张图里有哪些角色再动手画图而不是画完才想起配色。3. classDef语法拆解从定义到应用一条龙跑通3.1 定义格式与核心属性classDef的基础句式非常固定classDef 类名 属性:值,属性:值,属性:值;一个完整示例classDef startNode fill:#4CAF50,stroke:#333,stroke-width:2px,color:#fff;常见的可用属性我整理成了一张表属性作用示例值fill节点填充色#4CAF50、red、yellow等CSS颜色写法stroke边框颜色#333stroke-width边框粗细2pxstroke-dasharray边框虚线样式5 5rx / ry圆角半径6或10pxcolor节点内文字颜色#fff这里面有两个容易踩的细节。第一stroke-dasharray的值是空格分隔的两个数字表示实线段长度和空白段长度写成5,5或5,5px在某些渲染版本里不生效。第二rx和ry控制圆角但不同图表类型的支持程度有差异我在后面踩坑部分会说。类名本身的命名也有讲究。不要用中文、括号、引号这类特殊字符尽量用英文、数字、下划线并且首字母不要用数字。为什么因为classDef生成的样式最终会注入到SVG里作为一个CSS类类名不规范轻则让你自己念不出来重则碰到CSS解析边界问题样式悄悄失效。3.2 把类挂到节点上的三种姿势classDef定义好之后要把类挂到节点上有三种常用写法。第一种节点定义行直接加:::后缀。这个写法最直观flowchart LR A[开始]:::startNode -- B[处理中]:::processNode注意:::要紧跟在节点文本后面中间不要有空格。节点文本用哪种括号包围都行[矩形]、(圆角矩形)、{判断}都不影响挂类。第二种用独立的class语句批量应用。适合图已经画完、最后统一挂类的情况class A,B,C processNode把这条语句放在整个图的最末尾它会把节点A、B、C全部挂到processNode类上。如果一个类要挂十几个节点明显比一个个去节点行里加:::省事可读性也好。第三种在链接语句的两端节点上也可以直接挂类。比如A -- B{是否通过}:::branchNode这针对的是那种只在特定分支上需要特殊样式的节点不会影响其他引用同名的节点。三种姿势在同一个图里可以混用但建议同一张图不要混太杂小图用:::更直白大图用class语句集中管理更清晰。3.3 特殊用法default类名与全局样式classDef里有一个特殊类名default。它的作用是给所有没有显式挂类的节点套用统一样式。示例classDef default fill:#f5f5f5,stroke:#888,stroke-width:1px;写这么一行之后图里所有未指定样式的节点都会被改成浅灰填充、灰色边框。这个能力很实用尤其当你想让一张图从默认蓝色风格切换成某种中性的灰白风格时不需要逐个节点改只要加一行default定义即可。它也可以和具体节点的样式共存default负责打底特定节点通过:::或class语句单独着色两者不冲突。我自己的习惯是每张超过十五个节点的图都在开头先写一行classDef default做底色再写几个主要的业务角色类。这样即使后来忘给某个节点挂类它也不会以最刺眼的默认蓝出现在图里整体视觉始终统一。3.4 优先级与覆盖为什么样式老不生效classDef用着用着你大概率会遇到我明明定义了样式节点却不变色的情况。这里有两层规则必须先搞清楚。第一层同名类重复定义时后面的定义会覆盖前面的。所以如果你在图中两个位置都写了classDef start ...第二个会生效第一个被忽略。这种问题在复制粘贴大段代码时特别容易出现。第二层节点上的内联style语句优先级高于classDef。也就是说如果一个节点同时满足被classDef挂类和节点行后面单独写了style那个style会胜出。我建议排查样式问题时先把图里所有style语句全找出来看一眼比对着classDef猜半天快得多。另外提醒一句Mermaid主题变量也有一套默认样式classDef的优先级高于主题默认值所以正常情况下你用classDef改颜色应该是能压过主题的。如果你发现怎么改都不生效不要急着怀疑优先级先确认类名有没有拼错、:::有没有写成::、代码块标签是不是mermaid。十次里至少有八次是这类低级问题。4. 实战案例用classDef给订单流程做一个可读性翻倍的图4.1 先定视觉规范哪种节点用什么颜色别急着写代码先想清楚这张图里有哪些角色。我以最常见的下单到订单完成流程为例定义了五个样式类节点角色类名样式思路开始/结束startFinish绿色填充白色文字业务处理operation蓝色填充白色文字判断分支judgement橙色填充深色文字数据读写storage灰色填充虚线边框异常/提示exception红色填充白色文字这个配色规范不是随便定的。绿色代表安全进入流程又安全退出橙色代表需要人眼关注的分叉点红色代表可能出问题的地方灰色虚线代表数据落库而不是逻辑处理。约定好之后这张图不需要图例读者也能大致猜出颜色含义这就是视觉语言的作用。4.2 完整订单流程代码与说明下面是一段完整的Mermaid流程图直接复制就能在VSCode里渲染flowchart TD classDef startFinish fill:#4CAF50,stroke:#333,stroke-width:2px,color:#fff,rx:10,ry:10 classDef operation fill:#2196F3,stroke:#333,stroke-width:2px,color:#fff classDef judgement fill:#FFC107,stroke:#333,stroke-width:2px classDef storage fill:#9E9E9E,stroke:#333,stroke-width:2px,stroke-dasharray:5 5 classDef exception fill:#F44336,stroke:#333,stroke-width:2px,color:#fff A([用户提交订单]):::startFinish -- B{库存校验}:::judgement B --|有库存| C[扣减库存]:::operation B --|无库存| D[返回缺货提示]:::exception C -- E[(订单表写入)]:::storage E -- F{支付状态}:::judgement F --|支付成功| G[通知发货]:::operation F --|待支付| H[发送支付提醒]:::exception G -- I([订单完成]):::startFinish这段代码里值得注意几个细节。第一A([用户提交订单])用了双层括号渲染出来是体育场形状比普通矩形更适合表达起点终点。配合startFinish类的rx:10,ry:10节点圆角统一视觉亲和很多。第二E[(订单表写入)]用了[( )]语法渲染成圆柱形一看就知道是数据库或存储类组件再加上灰色虚线边框双重强调这里是落库操作。第三所有:::后缀都紧跟节点文本没有加多余空格。如果你复制这段代码发现某个节点样式没生效先检查是不是自己手敲时在:::前后加了空格。4.3 从流程图扩展到类图和ER图的思路classDef不止能用在流程图上。Mermaid的类图、ER图在较新版本里也支持样式类控制只是不同图表类型的支持程度有差异用法也要按图型调整。拿类图举例类图里的节点本身就是类你想把数据实体类画成一种风格、业务逻辑类画成另一种风格思路完全一样先定义两个classDef再用class语句把对应类名挂上去。这里要提个醒类图里class关键字太密集了定义类要用class User {}挂样式又要用class User,Order dataClass初学者特别容易绕晕。我建议在类图里先用小样本验证classDef能不能生效再往大图里铺开。不同Mermaid版本的文档差异也不小遇到类图样式不生效直接去查当前版本对应图型的官方文档比在论坛里翻老帖子靠谱。5. 踩坑实录classDef和VSCode预览里的那些坑5.1 现象一样式根本没生效怎么排查这是最常见的坑。完整排查链路应该是这样的先确认代码块语言标签是mermaid一个字都不能多不能少。检查classDef的类名和后面挂类用的类名是否完全一致包括大小写。startNode和startnode是两回事。检查classDef语句末尾有没有分号。属性之间用逗号整个定义用分号结束漏了分号在Mermaid里通常会直接报错。检查:::是不是写成了::或者后面多了空格。打开VSCode的开发者工具看控制台命令面板搜开发人员: 切换开发人员工具切到Console标签如果Mermaid渲染报错这里几乎都会有记录。如果以上都没问题逐个禁用其他Markdown相关插件重载窗口再试。我自己遇到最多的就是第2步——类名拼写不一致而且这种错误不报错纯粹是静默失败特别耽误时间。后来我养成一个习惯所有类名统一用小写开头比如start、operation、judgement避免大小写问题。5.2 现象二颜色被主题或编辑器覆盖显示不对有时候你定义的fill确实生效了但实际渲染出来的颜色跟你预期差很多。这通常是因为VSCode预览整体套了一层暗色主题或者Mermaid的主题变量把某些颜色做了映射。解决办法是在classDef里尽量写标准的6位hex颜色值少用red、blue这类CSS颜色名。裸颜色名在不同主题下的解析不完全一样在本地预览和发布后的站点上可能产生两种结果而hex值则稳定得多。如果你在暗色主题下觉得某些节点对比度不够不要硬调一个刺眼的高亮色更合理的做法是同时设置color文字颜色和fill确保深色填充配浅色文字、浅色填充配深色文字。图示可读性不只是颜色好看更取决于颜色之间的对比度。5.3 现象三本地预览正常发布到GitHub或GitLab就变样这是最多人被坑的一环。VSCode里插件使用的Mermaid版本和你文档发布平台内置的Mermaid版本可能差了好几个大版本。classDef最核心的fill、stroke、stroke-width、color这些属性基本各个版本都认但rx、ry、stroke-dasharray这类属性在某些平台的老版本里不一定生效。应对策略很明确关键语义不要押在高级属性上。比如你想区分数据库节点和普通节点只靠虚线边框识别就太脆弱换成同时填充不同颜色就算虚线在某个平台不渲染颜色差异也能保住信息层级。反过来讲这也是为什么我建议classDef里颜色设计要尽量遵循颜色即角色的原则而不是依赖某些花哨视觉效果。5.4 现象四特殊字符把classDef属性截断或报错最后一个高频坑是特殊字符。Mermaid代码里出现混乱的引号、反引号、中文标点轻则属性解析不到重则整段代码渲染失败。实际经验里有几条硬约束classDef类名和节点文本里不要用双引号不要用反引号。属性值里的#号必须紧跟hex颜色值中间不能有空格写成#4CAF50。节点文本用中文完全没问题但别在文本里用花括号{}和方括号[]这些是Mermaid的语法符号会被误判。stroke-dasharray的5 5中间必须是空格写成5,5在不少版本里识别不了。还有一条容易被忽略如果你从别人的博客或文档里复制Mermaid代码很可能把中文标点的逗号、分号复制进来表面上看着差不多解析器直接报错。遇到诡异报错时把相关行里所有标点重新用英文输入法敲一遍往往就好了。最后再分享一个我自己的习惯。每次画新图我都先只写节点和连线把流程结构想清楚确认无误之后再加classDef和:::。顺序反过来的话改一次结构就要牵连一堆样式改到最后心态容易崩。另外多节点图的classDef统一放在图的开头让所有风格定义集中在一个区域后面的人接手维护时不用翻完整张图才能找到某个样式是怎么来的。这就是我用classDef配合这个VSCode插件的完整心法希望对你有用。