ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

用HTML+SVG打造出版级架构图:开源项目diagram-design实战解析

用HTML+SVG打造出版级架构图:开源项目diagram-design实战解析 做技术的这些年我见过太多能把系统讲清楚、却把架构图画成一团乱麻的工程师。方框大小全凭手感连线穿来穿去不遵守任何规则颜色用得像是彩票开奖最后还要补一句“大概示意一下别在意细节”。直到我在GitHub的热评里刷到 diagram-design 这个项目才突然意识到架构图这件事根本不需要打开Visio也不需要求设计师出手纯HTMLSVG这条路完全能走到“出版级”的水准。diagram-design 不是一个在线画图网站也不是需要安装的桌面软件它是一套把架构图当作代码工程来做的开源思路用一篇结构良好的HTML页面作为载体用SVG作为绘图语言所有图形都是可缩放、可搜索、可被Git记录、可被CSS统一控制的矢量元素。适合谁画架构图嫌工具难看的后端工程师需要给方案配图的前端开发者写技术文档和PPT的技术博主以及虽然不懂设计、但是想让自己产出“看起来正式一点”的普通程序员。这篇文章我会从源码拆解到实操落笔把整个项目的设计思路和画图方法完完整整扒给你看。1. 这个项目到底在解决什么问题架构图不该是技术草稿1.1 从“能看懂”到“能出版”架构图的审美门槛架构图这件事本质上是把复杂系统的层级、依赖、数据流转化成一张二维的信息图。它有两个目标第一个目标是逻辑正确第二个目标是视觉可信。可惜大部分人在画的时候只完成了第一个目标。逻辑正确解决的是“信息不失真”但视觉可信解决的是“专业感”。同一套微服务架构用Word文本框画出来和用出版级排版画出来读者对方案质量的预期完全不一样。我在评审方案的时候见过太多这种情况方案本身设计得很周密结果架构图一放出来方框中心没对齐连线和边框穿插交错字体大小混乱整个评审的注意力全被图带跑了。这不是技术问题是信息设计的问题。diagram-design 给出的答案很简单把设计规范塞进代码里。它不像设计工具那样给一堆自由操作的按钮而是通过固定的栅格、统一的间距、内置的配色变量、可复用的SVG组件让一个完全没有审美训练的人也能按着规范画出看起来很专业的架构图。代码本身就是约束约束本身就是设计。1.2 diagram-design 的项目定位与核心特性这个项目在GitHub上的定位非常明确不使用任何图片素材不引入重量级渲染库不依赖联网服务用最基础的HTMLSVG能力输出可交付的架构图和示意图。和那些“拖拽式”的工具相比它有几个很核心的特点值得先说清楚代码即画布整个架构图就是一个HTML文件加几个CSS定义结构用SVG标签描述风格用CSS变量控制。改一个颜色全图联动改一个间距相关元素同步调整。矢量原生SVG是矢量格式放大到多少倍都不会糊。答辩投影、PDF打印、高分辨率屏幕截图都能保持清晰。版本可追踪架构图是纯文本源码放进Git仓库里每一次改动都有记录。同事想改模块名称直接提Pull Request审查逻辑就像审查代码一样清晰。工程化友好因为本质是网页它可以嵌入技术文档、可以放入Vue/React组件、可以用JavaScript动态生成数据绑定甚至可以做简单的点击交互。这个项目解决的最痛的点不是“画不出来图”而是“画出来的图没有设计感”。它把发表级图解拆解成了可执行的技术规范。你会看到它的源码里每个坐标都不是随手写的颜色都有对应的语义变量圆角和间距遵循统一规律。这就是源码级别的“设计系统”。1.3 与主流绘图工具的横向对比为了让你更直观地理解这个项目的定位我把日常画架构图常用的几种方案拉出来对比一下方案渲染方式默认审美版本管理可编程性离线可用Visio桌面渲染一般偏Office风格二进制文件无法Diff弱是draw.ioCanvas/SVG混合中等依赖模板XML文件勉强可读一般桌面版可PlantUML文本转图片偏草图感风格固定纯文本可Diff强是ExcalidrawCanvas手绘风不适合正式场合文件可同步一般网页需联网diagram-design纯SVG高内置设计约束纯文本可Diff强可嵌入前端是我用这个过程走下来最明显的感觉是draw.io胜在方便Visio胜在复杂图形管理但diagram-design赢在最终产出物的质感。它更像是一种“写给工程师的设计语言”让你绕开设计工具的学习成本直接用熟悉的HTML、CSS、SVG知识画出高水平结果。2. 源码解剖纯HTMLSVG的绘图基石2.1 SVG画布viewBox、width/height 与响应式翻开这个项目的源码首先看到的是那一大段结构严谨的HTML文件里面嵌着一个巨大的svg标签。这个SVG标签看起来不复杂却是整套绘图体系的地基尤其要读懂三个属性width、height和viewBox。width和height决定的是SVG在页面上的显示尺寸而viewBox决定的是内部坐标系统的范围。打个比方你在一张图纸上画图viewBox是图纸本身的幅面规格width/height是这个图纸被扫描之后在屏幕上显示的尺寸。知道这个区别以后很多疑惑就能解开了。diagram-design 的源码里常见的写法是这样的svg width1600 height900 viewBox0 0 1600 900 xmlnshttp://www.w3.org/2000/svg !-- 整个架构图都画在这个1600x900的坐标系里 -- /svg这里的viewBox0 0 1600 900后面四个数字分别代表坐标系起点x、起点y、坐标宽度、坐标高度。也就是说SVG内部所有坐标都是以1600和900为边界来设计的。这样设计最大的好处是当页面需要响应式适配时我可以把width和height改成百分比SVG会自动等比缩放而内部所有坐标不会被破坏。我实测下来就算把宽度从1600压缩到375像素的小屏幕图形整体缩小但结构和比例保持不变这就是viewBox的功劳。源码里还有一个细节xmlnshttp://www.w3.org/2000/svg。这个命名空间声明是SVG被浏览器正确解析的前提少了它有些浏览器会直接把SVG标签当未知HTML标签处理图形渲染直接失败。很多初学者把SVG代码复制到HTML里发现显示空白第一件事就该检查有没有这个声明。2.2 HTML容器与组件化组织栅格、Flex布局与SVG嵌入diagram-design 的结构精髓在于它不是把SVG孤立地放在页面上而是用HTML的布局能力给SVG做了一个完整的“排版容器”。源码里能看到栅格系统、Flex布局、CSS变量以及SVG组件之间的协同。项目源码中常见的页面组织方式可以抽象成下面这个结构main classdiagram-container header classdiagram-header h1订单中台微服务架构图/h1 p classsubtitlev2.3.1 | 2025-01-20 | 作者Architecture Team/p /header section classdiagram-body svg width1600 height900 viewBox0 0 1600 900 defs !-- 箭头、渐变、阴影等复用定义 -- /defs g idlayer-gateway !-- 网关层内容 -- /g g idlayer-service !-- 服务层内容 -- /g /svg /section /main用HTML负责“排版、标题、说明文字”用SVG负责“图形内容”这比纯SVG画整张图更容易维护。为什么因为主标题、版本号、日期这些信息用HTML写天然支持换行、支持SEO检索、可以方便地和文档系统联动。而SVG内部只关心图形结构职责更单纯。SVG内部则大量使用g标签做分组。每个分组代表一个独立模块或者一个独立图层并且通过id做了命名。比如layer-gateway代表网关层layer-service代表服务层。这种命名规范和HTML语义化是同一个思路既方便自己找代码也方便同事接手。项目源码里几乎找不到裸奔的rect所有图形元素都被包进有明确意义的g里这一点非常值得学习。2.3 视觉语言配色系统、字体层级、圆角与阴影看diagram-design的源码最让我感慨的是它把所有“审美判断”都变成了“变量定义”。这大概就是工程师做设计系统和设计师做设计系统不太一样的地方设计师可能只说“这个颜色很好看”而这个项目会直接写成CSS变量让整套图表共用一套色彩token。源码里通常能看到类似这样的CSS变量群:root { /* 主色与辅色 */ --color-primary: #2563eb; --color-primary-light: #60a5fa; --color-bg: #f8fafc; --color-surface: #ffffff; --color-border: #e2e8f0; --color-text: #0f172a; --color-text-sub: #64748b; /* 语义色 */ --color-success: #16a34a; --color-warning: #d97706; --color-danger: #dc2626; /* 间距栅格 */ --space-1: 8px; --space-2: 16px; --space-3: 24px; --space-4: 32px; /* 圆角与阴影 */ --radius-sm: 4px; --radius-md: 8px; --shadow-card: 0 1px 3px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.04); }这几组变量不是随便写的里面藏着信息设计的逻辑主色用于强调核心组件中性色用于背景和边框语义色用于标识不同状态的节点。间距采用8的倍数是为了让视觉上的留白保持节奏感。圆角控制在4px到8px是为了既显得现代又不失技术图表的硬朗。字体方面项目源码里通常会定义一个兼顾中西文的字体栈比如font-family: Inter, PingFang SC, Microsoft YaHei, sans-serif;。标题和正文的字号也会分梯度比如标题用24px模块名用18px说明性文字用14px。越重要的信息字号越大、字重越高这是信息层级的基本功但这个项目把它写成了规范任何人都能遵守。SVG内部虽然没有CSS的:root但可以通过style标签或者内联样式引用这些变量。比如一个模块方框的fill可以直接写成fillvar(--color-surface)这样全图的颜色改起来就是改一个变量的事。这就是源码级设计系统的威力。3. 实操从零产出你的第一张出版级架构图3.1 搭建基础的HTMLSVG骨架前面看了不少源码设计思路现在我们直接动手用diagram-design的方式从零画一张架构图。我带大家画一个典型的微服务系统架构图包含用户层、网关层、服务层和数据层。这张图画完你基本就能掌握这套方法的80%。首先搭建基础的文件结构新建一个architecture.html。文件头和样式照下面来!DOCTYPE html html langzh-cn head meta charsetutf-8 title订单系统微服务架构图/title style :root { --color-primary: #2563eb; --color-bg: #f8fafc; --color-surface: #ffffff; --color-border: #e2e8f0; --color-text: #0f172a; --color-text-sub: #64748b; --space-2: 16px; --radius-md: 8px; --shadow-card: 0 1px 3px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.04); } body { margin: 0; background: var(--color-bg); font-family: Inter, PingFang SC, Microsoft YaHei, sans-serif; color: var(--color-text); } .diagram-container { max-width: 1600px; margin: 40px auto; padding: 32px; background: var(--color-surface); border: 1px solid var(--color-border); border-radius: 12px; box-shadow: var(--shadow-card); } .diagram-header h1 { margin: 0 0 8px; font-size: 24px; } .diagram-header p { margin: 0 0 24px; font-size: 14px; color: var(--color-text-sub); } .diagram-body svg { width: 100%; height: auto; display: block; } /style /head body main classdiagram-container header classdiagram-header h1订单系统微服务架构图/h1 pv1.0.0 | 业务中台组/p /header section classdiagram-body !-- SVG画布放这里 -- /section /main /body /html这个骨架的作用是先把外部排版定好让SVG能在最舒适的视觉范围内呈现。注意.diagram-body svg里的width: 100%; height: auto;这个设置很关键它让SVG自适应容器宽度同时通过viewBox保持宽高比屏幕大时放大屏幕小时缩小永远不会变形。3.2 四步画出模块分区、容器、连线与箭头接下来进入正题在空白的SVG里一步步绘制架构图。第一步绘制分区背景。一个标准的架构图先要有“图层感”。我们在1600x900的坐标系里为四层分别画一个底色块。这里用半透明或者浅色填充要让背景色既能区分层次又不抢前景模块的风头。svg width1600 height900 viewBox0 0 1600 900 !-- 用户层背景 -- rect x40 y40 width1520 height140 rx12 fill#eff6ff / !-- 网关层背景 -- rect x40 y210 width1520 height140 rx12 fill#f0fdf4 / !-- 服务层背景 -- rect x40 y380 width1520 height360 rx12 fill#faf5ff / !-- 数据层背景 -- rect x40 y770 width1520 height100 rx12 fill#fef2f2 / /svg每个分区左上角的坐标和高度都是算过的层与层之间留了30px的间隔底部留了足够的空间画数据存储。rx12让背景块变成圆角矩形比直角矩形更柔和这是现代图表设计的常见处理diagram-design源码里几乎所有矩形都有圆角原因就在这里。第二步放置模块框。背景有了接下来在每一层里放具体的模块。模块框由两部分组成一个rect矩形一组text文字。矩形的职责是提供视觉容器文字的职责是表达信息两者通过g分组绑定在一起。!-- 用户层模块 -- g transformtranslate(80, 75) rect width200 height70 rx8 fill#ffffff stroke#2563eb stroke-width2 / text x100 y40 text-anchormiddle font-size18 font-weight600 fill#0f172aWeb端/text /gtransformtranslate(80,75)这一步很关键移动图形时不需要重新计算矩形和文字的绝对坐标只需要把整个组平移到新位置组内所有元素跟着动。文字居中也很省事x100取的是矩形宽度的中间值加上text-anchormiddle文字就水平居中了。垂直方向y40大约是矩形高度70px的上半部分偏下一点视觉上刚好居中这个数值是经验值实际可以微调。第三步画连线和箭头。模块之间靠连线表达依赖关系。SVG里最简单的连线是line但真实架构图的连线不可能都是直线因为模块之间会有前后的遮挡关系。diagram-design的策略是“尽量走正交线”就是横平竖直的折线这样看起来最规整。defs marker idarrow viewBox0 0 10 10 refX9 refY5 markerWidth6 markerHeight6 orientauto-start-reverse path dM 0 0 L 10 5 L 0 10 z fill#2563eb / /marker /defs !-- 从Web端指向网关层的连线这里用折线走直角 -- path dM 180 145 L 180 180 L 160 180 L 160 210 fillnone stroke#2563eb stroke-width2 marker-endurl(#arrow) /marker这个定义我再展开讲一下它相当于给线的末端装了一个“箭头模具”。viewBox0 0 10 10定义了箭头图形的坐标范围refX9 refY5决定了箭头和线段接触的位置orientauto-start-reverse保证箭头自动跟随线的方向旋转。有了这个定义后面所有需要箭头的连线只要在marker-end里引用同一个url(#arrow)就行不需要重复画箭头这是源码里复用思想的典型体现。第四步加文字标注和辅助信息。架构图里除了模块名称通常还需要额外说明分组职责、链路方向、版本信息。这些文字在SVG里用text画但要注意别把大段文字塞进图里应该用短词加图例的方式处理。比如在网关层背景块右侧加一行小字标注“统一流量入口”text x1500 y250 text-anchorend font-size14 fill#64748b统一流量入口/text辅助信息的作用是让看图的人不需要你口头解释就能明白每一层的定位这属于出版级图解的标配。它的排版原则是字号比模块名称小颜色用次级文字色位置放在层背景的角落绝不能和模块主体抢视觉焦点。3.3 从“能看”到“出版级”质感打磨的五个细节画完四步架构图已经从零成型了。但如果你只想停在这里那还远没到“出版级”。diagram-design的精髓有一大半在细节里我梳理了五个打磨要点细节一对齐。所有模块的坐标尽量取整并且让相同层级的模块拥有相同的y坐标或x坐标。比如用户层的三个入口模块y坐标都是75x坐标按等间距递增这样一眼看过去就是齐整的。不要出现“差两三个像素没对齐”的歪斜感那是粗糙感的最大来源。细节二留白。模块框内的文字周围要有空间我习惯文字上下至少留16px左右至少留20px。矩形不是越大越有存在感而是该贴合内容。很多工具默认生成的框图黑洞洞地撑满整块这是视觉压抑的源头。细节三颜色克制。一张图里主色加辅色不要超过5种。diagram-design用语义色做层级区分比如主服务用蓝色外部依赖用灰色异常或告警节点才用红色。颜色不是为了装饰而是为了引导视线。细节四阴影用对。阴影能增加卡片的层次感但别用成重度投影。我推荐类似源码里的0 1px 3px rgba(0,0,0,0.08)这种轻量阴影远处看是淡淡的一层悬浮感近处看不会脏。SVG里的投影用filter定义一次之后通过filterurl(#shadow)反复引用。细节五图层命名。这一点最容易被工程师忽略。给每个g设置清晰的id比如layer-user、service-order并且配合注释说明这个图层的内容。等到需要修改某个服务的位置时可以直接在编辑器里搜索idservice-order瞬间定位不用对着几千行源码人肉翻找。4. 常见问题与排查技巧实录4.1 浏览器渲染不一致字体和箭头最折磨人我用diagram-design的方式画图踩过最大的坑是SVG在不同浏览器的渲染细节不一致。Chrome渲染的text文字清晰利落换成Firefox之后字体位置可能略微偏上或偏下Safari对marker箭头的大小处理也和其他浏览器不太一样有时候箭头会突然变得很小或者位置偏了。问题的根源在于每个浏览器对SVG特性的实现存在微小差异加上字体的行高计算规则不同导致文字在y方向的基准线偏移。我的排查思路是先锁定范围。如果只是文字位置偏移就把dominant-baselinecentral加到text标签上让文字以“中心线”而不是“基线”对齐。如果箭头大小不稳定就不要完全依赖markerWidth和markerHeight改用viewBox固定箭头图形同时把markerUnits设置为userSpaceOnUse这样箭头尺寸不会被线条宽度放大或缩小。我实测下来最稳妥的方式还是做完图后专门开Firefox和Safari各检查一遍。不要嫌麻烦出版级意味着你要交付的不仅是“符合标准的代码”还包括“在这个环境下看到正常效果”的保证。4.2 导出PDF和打印字体和缩放不能凭默认设置画完的架构图需要放进方案文档里很多人直接浏览器打印成PDF结果发现打印出来的字体发虚、页面被截断、颜色和屏幕差异巨大。这三个问题是高频翻车现场。字体发虚的根源是打印预览里字体被浏览器重新渲染加上屏幕到打印的颜色模式转换会损失对比度。解决办法分两步第一步SVG内部不要依赖网络字体尽量用系统字体栈因为打印环境可能无法加载网络字体第二步如果对效果有极致要求可以把文字转换成路径但SVG原生不支持需要导入到Vec命令或者用脚本做转换这个操作比较重通常我只用于最终交付印刷场景。页面被截断的问题一般是SVG宽度超出了打印纸张的可打印范围。我的处理方式是在CSS里加一套打印样式media print { .diagram-container { max-width: 100%; margin: 0; padding: 0; border: none; box-shadow: none; } .diagram-body svg { width: 100%; height: auto; } }这里面的逻辑是打印时去掉容器边距、边框、阴影只保留纯图形同时让SVG宽度适应纸张内容区宽度。打印前先用浏览器自带的打印预览看一眼分页情况如果需要精确分页可以把SVG分成几个小节每个小节一个独立的SVG画布但这种调整会影响整体布局我一般只在文档系统支持分节时用。4.3 团队协作与版本管理SVG源码不是给人肉看的架构图实际上是个“活文档”系统演进、模块拆分、依赖变化都要求图跟着更新。用SVG源码做的架构图最大的优势是能被Git追踪但同时也带来一个新问题团队里不是每个人都熟悉SVG语法。我在实际协作中总结了几条顺手的规矩。第一SVG代码里必须写注释。每个图层、每个复杂组件都要有明确注释说明它的业务含义比如!-- 订单服务负责下单流程 --这样队友不用逐行解析SVG标签就能知道这个区域是干嘛的。第二统一格式化和命名规范。多人修改同一个SVG文件时如果格式不统一Diff会变得非常痛苦。我们团队固定使用Prettier来格式化HTML和CSSSVG标签内部的属性顺序也约定好谁改完都跑一遍格式化再提交这样Diff记录里只有真正的改动。第三把重复使用的图形元素抽到defs里。比如公司Logo、图例说明、统一的数据库图标都定义成symbol或者g id...。后续改一次定义全图同步更新不会出现改了5个地方还漏了2处的尴尬。这个习惯我从diagram-design的源码里学到后基本上每张图都会遵守。最后再分享一个小技巧在我的实际使用过程中最上瘾的一点是diagram-design这种思路完全改变了画架构图的工作流。以前画图是打开工具、拖矩形、调样式、导出图片现在画图是写代码、定义变量、组织组件、提交Git。同样是画一张订单系统架构图老路子可能要半小时新路子第一次可能慢一点但一旦你沉淀出自己的模块库和配色变量后面的产出效率会高到离谱。如果你刚接触这套方案我建议不要一上来就画复杂的大系统先拿一张自己最熟悉的模块图练手把SVG的rect、text、path、marker这四个基础元素用熟再把diagram-design源码里的CSS变量复制过来改造自己的配色。等你能不看文档画出第一张图的时候你会明显感觉到架构图不再只是“给程序员看的草图”它真的可以变成一份有设计感、有专业度的交付物。
返回列表