拓冰建站拓冰建站
首页 / 资讯中心 / 正文

纯HTML+SVG架构图方案:源码拆解出版级图解设计与落地实践

今天想聊一个我在GitHub上翻到的项目叫 diagram-design。先说结论如果你画过架构图应该懂那种痛——框线对不齐、箭头歪歪扭扭、字体忽大忽小、颜色辣眼睛整套图做出来连自己都不忍直视。而这个项目主打的概念恰好戳中这个痛点纯 HTML SVG就能产出连设计师看了都点头的出版级图解。它不是传统的自动布局引擎也不是又一个“套模板”的图表工具。它的核心思路是用 HTML 管理结构、用 SVG 负责图形绘制把每一根线条、每一个文字当成设计元素去打磨最终输出的图不是“能看”而是“耐看”。这篇评测我不会只停留在“这个项目很牛”的层面而是直接从源码出发拆解它的设计思路、SVG 技术细节、落地实操步骤以及我在试用过程中踩过的坑。无论是想提升技术文档质感的后端工程师还是被架构图折磨的前端开发这篇文章应该能给你一些真正能拿走的思路。1. 设计思路与技术选型为什么是纯HTMLSVG1.1 先说说市面上那些“画架构图”的方案为什么总差一口气我接触过不少画架构图的方案大致可以分成几类。第一类是手绘或者用画图软件硬拼比如 Visio、draw.io、PowerPoint甚至直接用 Figma。这类工具的问题在于图是静态的一旦业务逻辑变化整个图要从头改而且很多人用这类工具画出来的图基本没有统一的排版规范框的大小靠手拖线的位置靠眼神看起来就像几个人各画各的再拼到一起。第二类是自动化生成方案比如 Mermaid、PlantUML、Graphviz。它们的优点是上手快写一段文本就能生成图适合展示依赖关系、时序流程。但缺点也相当明显排版算法是固定的你想微调一个节点的位置往往要跟布局引擎做斗争。Mermaid 里的节点位置基本不可控Graphviz 的 dot 布局在复杂场景下更是灾难生成的图经常交叉线满天飞离“出版级”差得很远。第三类是基于前端绘图库的比如 D3.js、AntV G6、mxGraph。这类方案功能强大自由度极高但也意味着学习曲线陡峭。你要是只为画一张架构图引入一个几百 KB 的绘图引擎后续维护成本也高。团队里不是每个人都愿意读 D3 的源码去调一个连线路径。diagram-design 选择了完全不同的路线不搞自动布局不引入重型绘图库而是把 SVG 当作最终的画布用 HTML 来组织结构化信息然后用 CSS、少量脚本去精确控制每一个图形的样式与位置。它的核心信条是架构图不是数据可视化的图表它更像一张“设计图”所以要像做设计一样去排版。1.2 “纯HTMLSVG”不是退而求其次而是一种克制很多人觉得 SVG 只是“能放大缩小的图片格式”其实它远比我们想的强大。SVG 本质是 XML意味着图形可以像 DOM 一样被 JS 操作、被 CSS 样式化、被屏幕阅读器读取。这就是 diagram-design 选它的根本原因矢量无损缩放不糊CSS 完全可控想要什么风格都能写出来DOM 事件天然支持悬停、点击、动画都像做网页一样自然。HTML 在这里起什么作用它在 SVG 之上做“结构层”。比如说一个架构图节点本质上是一个容器它里面有图标、标题、描述文字、状态标签。如果用原生 SVG 手写这些组合代码会非常繁琐维护起来更是痛苦。而用 HTML 定义好节点的结构模板再用 SVG 画边框、背景、连线和箭头两者配合正好各自发挥长处。这套组合还有一个隐形的优势团队协作友好。设计师改样式时可以直接改 CSS 变量不会动到图形逻辑开发改结构时只用调整 HTML 模板不需要碰无数个 path 节点。实测下来这种“HTML 管结构、CSS 管样式、SVG 管图形”的分层比在单个 SVG 里硬啃所有事情要舒服得多。1.3 什么样的场景适合用它什么样的场景不适合诚实地讲diagram-design 不是万能的。如果你要画的是海量节点图比如上千个服务器的拓扑图、全网链路状态图它可能不是最优解——因为 SVG 的 DOM 节点一旦数量上去了浏览器渲染性能会明显下降。这种情况Canvas 或者 WebGL 的绘制方案更合适。但如果你要画的是系统架构图、业务模块图、技术方案汇报图、数据流向示意图节点数量通常控制在几十个以内这类图的痛点不是“渲染不过来”而是“画得不好看、改起来麻烦”。diagram-design 的定位恰好落在这一区间强调设计质量、可维护性、可控排版。它最适合的场景就是“需要反复迭代、给团队或客户看的架构图”。2. 源码核心解析那些让SVG实现出版级效果的细节2.1 项目结构一个典型的前端组件库形态把源码 clone 下来之后我第一件事就是看目录结构。diagram-design 的工程组织比较规整大致是这么划分的src/components核心图形组件比如节点、连线、分组框、箭头、标签等src/layout布局辅助逻辑以“计算节点坐标”“计算连线路径”为主src/themes主题与设计令牌包括颜色、字号、间距等src/utils工具函数比如坐标变换、路径生成、SVG 序列化examples示例代码适合快速上手docs说明文档这种划分符合绝大多数前端组件库的习惯。但有几个细节值得注意themes被独立成目录并且大量使用 CSS 变量Custom Properties来管理设计令牌。这是它做到“设计师也认可”的基石之一——颜色、圆角、阴影、字体大小全部集中管理而不是散布在几十个文件里。换主题就像换皮肤一样简单。还有一点layout和components是分离的。这意味着你可以在不改变组件结构的前提下替换整套布局算法。项目内置的布局函数不多核心是“盒式布局”和“分层布局”但它们都遵循同一个接口传入节点与连线关系返回坐标与路径。这个设计让项目保持清晰的同时也方便二次定制。2.2 坐标系统与 viewBox为什么你的SVG一缩放就糊它却不糊很多人在手写 SVG 时都会遇到一个玄学问题在某个尺寸下看着没问题放大或缩小后文字糊了、线条位置跑了。这通常不是 SVG 的锅而是 viewBox 和宽高没配合好。diagram-design 的做法很严谨。它始终基于一个固定的逻辑坐标系通过viewBox来映射到实际渲染尺寸。比如定义viewBox0 0 1200 800那么无论容器是 600px 宽还是 2400px 宽内部坐标都按 1200×800 的逻辑空间来计算。所有文字、边框、间距都基于这个逻辑坐标因此任何缩放都不会产生失真。代码层面它封装了一个SvgCanvas组件大致逻辑是这样的function SvgCanvas({ width, height, children }) { return ( svg xmlnshttp://www.w3.org/2000/svg viewBox{0 0 ${width} ${height}} preserveAspectRatioxMidYMid meet width100% height100% {children} /svg ); }这里preserveAspectRatioxMidYMid meet意味着等比缩放、居中显示。如果宽高比不一致宁可留白也不拉伸。这个细节很重要很多粗糙的 SVG 图就是因为在不同容器里被拉伸变形才有了“廉价感”。还有一个容易被忽略的点vector-effectnon-scaling-stroke。SVG 里的线条粗细默认会随着缩放变化放大 2 倍后 1px 的线会变成 2px导致整体视觉失衡。diagram-design 在画架构图边框和连线时普遍使用了这个属性让线宽始终保持一致视觉上才稳得住。2.3 文本排版出版级的根基在文字不在图形说到“出版级”很多人以为拼的是配色和渐变其实真正拉开差距的往往是文字排版。diagram-design 在文本处理上下了不少功夫主要体现在几个方面。第一是字体栈。它没有使用系统默认字体而是定义了一套适合屏幕阅读与打印的字体栈--font-sans: -apple-system, BlinkMacSystemFont, Segoe UI, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Helvetica Neue, Arial, sans-serif;这套字体栈把苹果系、微软系、中文常见字体都覆盖了能保证在不同操作系统下都显示得舒服。中文场景下PingFang SC和Microsoft YaHei的优先级也让字形干净很多。第二是字号阶梯。所有字号不是随手写的而是按照 14 / 16 / 20 / 28 / 36 的阶梯来组织。标题、副标题、正文、注释各归其位一眼看过去层次分明。实际阅读体验中这种比例关系比“看图时觉得字大一点小一点都行”的随意编排要稳定太多。第三是文本锚点与对齐。SVG 的text元素默认是基线对齐容易造成“文字飘起来”或“坠下去”的错位感。diagram-design 在文本组件里严格设置了dominant-baseline和text-anchor并且封装了居中对齐、左对齐等场景。尤其在中英文混排的情况下基线不统一非常扎眼这个细节解决了大问题。第四是行高与间距。虽然 SVG 的text不支持 CSS 的line-height但 diagram-design 通过多行tspan手动计算行距并使用dy偏移实现。所有行距值与字号的比值固定通常控制在 1.4 到 1.6 之间跟网页排版习惯保持一致。2.4 栅格系统与间距令牌让每张图都“对齐强迫症”友好设计师看一张图顺不顺眼很多时候不看创意看“对齐”。diagram-design 内部默认使用 8px 栅格系统。也就是说所有节点坐标、间距、线宽、圆角半径都尽量取 8 的整数倍。这听起来很死板但实践下来8px 栅格能极大降低“看起来乱”的概率。为什么是 8 而不是 10因为 8 能同时被 2 和 4 整除奇数缩放场景下也可以保持整数像素对齐不会出现半像素渲染导致的模糊。间距令牌也做了抽象常用的有小间距8px用于图标与文字之间的间隔中间距16px用于节点内部区块间的分隔大间距24px用于节点与节点之间的留白分组间距32px用于分组框之间的区域划分这种靠令牌控制间距的方式让整个图的空间节奏高度一致。哪怕你换了主题、改了配色只要令牌体系不变视觉上的协调感就不会垮。2.5 组件化与数据驱动图不是“画”出来的是“算”出来的diagram-design 很核心的一个理念是架构图应该由数据驱动生成而不是手动摆放后导出一张死图。源码里所有图形组件比如ArchNode、ArchEdge、ArchGroup都是纯组件接收的结构化数据决定它们的布局和样式。举个例子一个节点组件的输入数据大致长这样const node { id: gateway, title: API 网关, desc: 统一流量入口负责鉴权与转发, icon: shield, status: active, x: 80, y: 120, width: 240, height: 96, };组件拿到这份数据后自动生成对应的 HTML 结构、CSS 类和 SVG 图形。位置、尺寸、状态决定渲染结果。这意味着你可以把图的数据存成 JSON放到仓库里做版本管理。业务变化了改数据就行不需要打开任何绘图软件。我当时测试的时候把一份写死的架构图改成了一个远程数据源改数据即时刷新渲染。这个模式对团队协作特别友好——产品、开发、运维各改各的数据图永远不会因为“某个人改一下别人的框”产生合并冲突。3. 从源码到落地实操一个可复用的架构图工程3.1 环境准备与项目初始化实际跑起来不算复杂。项目基于 Node.js 和现代前端构建工具Vite 或 Webpack 均可依赖很少核心就是 React用于组织组件和 SVG 相关工具库。如果你不用 React也可以参考它的纯函数实现思路移植到 Vue 或者原生 JS 中。初始化步骤大致如下git clone https://github.com/your-name/diagram-design.git cd diagram-design npm install npm run dev跑起来之后examples目录里已经有现成的示例图可以直接在浏览器看到效果。我没有全部翻完源码但光看示例的代码组织就能明显感觉到作者是长期被“丑架构图”折磨过的人——每一个参数、每一个布局函数都在解决实际痛点而不是为了炫技。3.2 实战从数据到一张三层架构图为了验证它的实际能力我照着源码的 API 写了一张典型的电商系统架构图包含接入层、业务层、数据层。先定义数据const layers [ { id: access, title: 接入层, nodes: [ { id: nginx, title: Nginx 集群, desc: 负载均衡 / 静态资源 }, { id: cdn, title: CDN, desc: 边缘加速 }, ], }, { id: biz, title: 业务层, nodes: [ { id: user, title: 用户服务, desc: 注册 / 登录 / 权限 }, { id: order, title: 订单服务, desc: 下单 / 扣库存 }, { id: product, title: 商品服务, desc: 商品信息 / 搜索 }, ], }, { id: data, title: 数据层, nodes: [ { id: mysql, title: MySQL 主从, desc: 核心业务数据 }, { id: redis, title: Redis 缓存, desc: 热点数据 / 会话 }, { id: es, title: Elasticsearch, desc: 商品检索 }, ], }, ];然后渲染ArchitectureDiagram data{layers} themelight /就这么简单图就出来了。生成的结果里每个节点都是独立的组件外层有分组框连线根据节点间的依赖关系自动生成。我特意试了修改节点之间的依赖和位置参数发现输出始终保持着同一个视觉基准不会因为多一个节点就整体失衡。3.3 主题定制如何适配自己的品牌色调开箱即用的默认主题是浅色模式观感接近设计规范里的“干净白底 高饱和强调色”。但实际业务大多需要自己的品牌色。diagram-design 的主题机制很直白用 CSS 变量覆盖默认值即可:root { --diagram-bg: #f7f9fc; --diagram-panel-bg: #ffffff; --diagram-line: #d0d7e2; --diagram-text-primary: #1a1a2e; --diagram-accent: #4361ee; --diagram-success: #2ec4b6; --diagram-radius: 12px; --diagram-shadow: 0 4px 12px rgba(26, 26, 46, 0.08); }把这段变量替换成自己的品牌色整张图的氛围立刻就变了。我实际测试过暗色主题只需要再加一套[data-themedark]变量覆盖图表的可读性保持得很好不会出现某些工具里“暗色模式只是把背景换黑文字跟背景糊在一起”的问题。主题这块设计得好的另一个体现是状态色也是令牌化的。success、warning、danger、info全部预置节点状态变化时不需要逐一手动调整文字和边框颜色组件会自动从状态映射到对应的令牌。3.4 交互能力扩展从静态图到可交互面板一张架构图如果只是静态图价值会大打折扣。我在源码基础上做了几次扩展验证了这套 SVG 方案的交互灵活性。首先是悬停高亮。因为 SVG 节点支持 CSS:hover所以只需要给节点添加一条样式.diagram-node:hover { filter: drop-shadow(0 0 6px rgba(67, 97, 238, 0.4)); stroke-width: 2; }效果立竿见影。其次是点击联动。我给节点绑定了onClick事件点击某个服务节点时右侧面板展示该服务的详细信息。因为底层是 React 组件树状态管理非常顺手不需要像操作 Canvas 那样手动管理重绘区域。再就是 tooltip。实现一个跟随鼠标位置的提示框在 SVG 里绑定onMouseMove用getBoundingClientRect换算坐标就行。这些交互在“静态导出图”时代完全不敢想但到了 SVG 组件化时代架构图变成了一种可交互的“文档”。这也是为什么我越来越看好这类方案——它把“画图”升级成了“构建信息面板”。4. 实战踩坑与排查技巧4.1 字体渲染不一致同一张图Windows 和 macOS 看起来不一样这是我第一个踩到的坑。同样的代码在 macOS 上显示锐利清晰在 Windows 上字体偏小、偏细甚至某些字体缺失导致回退到宋体观感直接崩塌。排查下来原因有两个。第一是字体栈优先级问题需要把Microsoft YaHei放到更靠前的位置或者干脆专门为 Windows 定义一套字体变量。第二是 Windows 对部分字体字重的渲染偏细需要把标题字号调大 1-2px或者改用更粗的字重。实际操作中我建议在项目里加一个平台检测动态调整样式const isWindows navigator.platform.toLowerCase().includes(win) || navigator.userAgent.includes(Windows);然后通过给根容器添加platform-win类微调字重和字号。这个处理很糙但在团队文档场景下够用至少保证 Windows 同事看到的图不再像“低配版”。4.2 SVG 导出 PNG 模糊明明矢量图导出图片却发虚SVG 在浏览器里显示没问题但一旦导出成 PNG 用于 PPT 或在线文档很容易出现文字发虚、线条模糊。原因在于导出时的像素密度不够。如果导出工具按 96dpi 生成1 个逻辑像素对应 1 个物理像素在 Retina 屏上自然模糊。解决办法是把导出的画布尺寸乘以一个倍率系数。比如用canvas.toBlob导出之前先把 SVG 的尺寸放大 2 倍甚至 3 倍function exportPng(svgElement, scale 2) { const rect svgElement.getBoundingClientRect(); const width rect.width * scale; const height rect.height * scale; // 将 SVG 序列化后画到对应尺寸的 canvas 上再导出 }不同场景对清晰度的要求不一样。投屏、PPT 场景建议 2 倍打印场景建议 3 倍以上。如果你用的是浏览器自带的“截图”方式那基本无解高清导出还是要自己写一套序列化逻辑。4.3 SVG 文本不自动换行长标题和描述该怎么处理这是 SVG 最让我难受的一点。DOM 里的文字超宽了会自动换行或者溢出隐藏但 SVG 的text元素不会。它只会无限向右延伸然后被挤出画布。diagram-design 里内置了一个文本截断和自动换行的函数大致思路是先度量文本宽度如果超出容器就按字符宽度切分生成多个tspan用dy逐行偏移。中文场景下按字符切分英文场景下按空格切分。实测这个函数在纯文本场景下够用但遇到中英文混排时偶尔会切出奇怪的位置。后来我改成了先调用Intl.Segmenter做语素切分再结合字符宽度判断切分准确度提升很多。如果你主要画中文架构图建议在这里加一层中文处理逻辑。4.4 可访问性让屏幕阅读器能读懂图架构图对视力障碍人群来说天然不友好。但如果用了 SVG至少可以做一部分渐进增强。diagram-design 的组件自动给生成的svg添加了roleimg和aria-label含义是“把整张图当作一张带说明的图片”。同时每个节点在渲染时保留了原始数据中的语义信息帮助阅读器朗读“哪个节点、什么职责”。这里我建议大家不要只依赖原生 SVG 的可访问性特性还可以在节点上加上title子元素鼠标悬停时也能显示原生 tooltip。虽然现代浏览器的原生 tooltip 样式很丑但它对辅助技术的兼容性最好。4.5 节点数量增多时性能下降明显实测中当单张图节点超过 200 个时SVG 的 DOM 数量会让交互出现卡顿。这是 SVG 方案的固有瓶颈。diagram-design 做了一些优化比如对不可见区域内的节点不渲染对连线采用贝塞尔曲线的简化计算但天花板还是存在。如果你的场景真的需要画几百上千个节点我建议不要硬用 SVG。可以考虑把整体图拆成多个 SVG 图层平铺或者换用 Canvas 渲染方案。这也是我在前文强调“这个项目适合中型架构图”的原因选工具一定要看场景边界。5. 上手后的几点实践体会5.1 真正让架构图“出版级”的不是工具是规范用过 diagram-design 之后最大感受是它提供的不是“一个画图组件”而是一套“画图规范”。栅格系统、字体阶梯、间距令牌、状态色映射这些才是让一张图从“能看”到“耐看”的分水岭。就算你完全不用这个项目把它这套设计原则抄到自己项目里同样能提升架构图质量。我后来在自己的团队文档里专门按照它的规范整理了一份“架构图排版指南”要求所有技术方案的配图必须遵循 8px 栅格、统一字号阶梯、使用语义化状态色。效果非常明显评审会上被吐槽“图看不清”的次数急剧下降。5.2 数据驱动是架构图长期维护的唯一出路以前用画图工具做架构图最大的痛点是“图永远赶不上代码变化”。diagram-design 把图变成数据驱动的产物之后维护成本降了一个量级。业务模块变更只需改 JSON 数据重新渲染图不会因为有人手动拖动位置而累积偏差。这一点在我看来是这类项目对团队最大的价值。我现在已经把核心系统的架构图数据放到了代码仓库里每次业务变更顺手更新一下数据文档渲染自动同步。整个过程不需要打开任何绘图软件也不需要求设计师帮忙“微调一下配色”。5.3 后续值得扩展的方向我打算在现有基础之上把这份架构图数据接入到自动生成 CI 流程中让每次构建后都产出一份最新的架构图快照方便追溯版本变化。同时也考虑把手画的架构图识别转换成 diagram-design 的数据格式进一步降低录入成本。如果你也在维护一份经常过时的架构图文档强烈建议关注这个方向它真的能让文档“活”起来。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门