deepseek 总结的html绘图规范

版本:v2(汇总至第 40 轮迭代)
参考原型:https://martinbj2008.github.io/html/fib_animation.html
适用场景:Linux 内核数据结构关系图(数组 / 链表 / 树 / 注册表)的静态 SVG 绘制


1. 参考原型:martinbj 的 FIB 画页

打开原页面,可以提炼出以下视觉约定(本项目沿用了其中大部分):

元素 martinbj 做法 本项目沿用 / 调整
页面容器 白色圆角卡片 + 浅灰背景 沿用
顶部信息 大标题 + 一行灰色说明 沿用(改为中文 title + commit 引用)
节点 圆角矩形,标题栏 + 内容区 沿用
节点配色 不同协议不同色 沿用
节点间关系 曲线 + 箭头 沿用(改为黑色)
内容字段 字段 : 值 键值对 沿用(callbacks 例外,见后文)
底部 配套代码区 按需保留

关键取舍:martinbj 是动画页(节点移动/重排),本项目只画最终状态,不做任何 animate 元素。


2. 总体设计原则

# 原则 说明
P1 静态优先 不做动画,只画最终状态
P2 分层递进 顶部声明 → 数组/链表 → 箭头 → 节点展开 → 底部代码(可选)
P3 一图一焦点 主图只表达”注册关系”,代码/结构体定义放两侧或底部辅助
P4 对齐严谨 箭头端点、框宽、列宽必须像素级对齐
P5 配色有语义 同层元素同一套配色规则;不同协议用色相区分
P6 极简冗余 不写”(指针)”、”(详情)”这类废话
P7 可缩放无滚动 SVG 用 viewBox + CSS width:100%,页面不自带滚动条

3. 页面布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
┌──────────────────────────────────────────────┐
│ Title(大标题,蓝色加粗 20px) │
│ Subtitle(一行说明 + 引用 commit / 源文件) │
├──────────────────────────────────────────────┤
│ const struct net_offload __rcu *inet_offloads[...] __read_mostly; │
│ ┌──┬──┬──┬───┬──┬───┬──┬──┬──┬─────┬──┬──┐ │ ← 数组条
│ │ │..│IPIP:4│..│TCP:6│..│UDP:17│..│255│ │
│ └──┴──┴─────┴──┴─────┴──┴─────┴──┴───┘ │
│ │ │ │ │ │ ← 黑色箭头
│ ▼ ▼ ▼ ▼ │
│ ┌────────┐┌────────┐┌────────┐┌────────┐ │
│ │ipip_… ││tcpv4_… ││udpv4_… ││gre_… │ │ ← 节点展开框
│ │callbacks│callbacks│callbacks│callbacks│ │
│ │ ╭────╮ ││ ╭────╮ ││ ╭────╮ ││ ╭────╮ │ │ ← 虚线明细框
│ │ │fn :│ ││ │fn :│ ││ │fn :│ ││ │fn :│ │ │
│ │ ╰────╯ ││ ╰────╯ ││ ╰────╯ ││ ╰────╯ │ │
│ └────────┘└────────┘└────────┘└────────┘ │
└──────────────────────────────────────────────┘

4. 视觉规范

4.1. 字体

元素 字体 字号 字重 颜色
页面 Title Arial 20px bold #1565C0
页面 Subtitle Arial 12px normal #666
顶层声明 monospace 14px normal(见「顶层声明的粗体」) #000000
数组格内容 monospace 9px bold 按协议配色
节点名(标题栏) monospace 12px bold 按协议配色
分组标签(如 callbacks) monospace 11px bold #1565C0
明细字段名 monospace 11px normal #555
冒号 monospace 11px normal #888
明细字段值 monospace 11px bold 按函数配色
代码区 monospace 12px normal #333 / #555

4.2. 配色

数组条(统一黑框,无背景色)

  • 外框:#333 1.5px
  • 空槽分隔:虚线 #B0BEC5,stroke-dasharray="2,2"
  • 有指针的格子分隔:实线 #333 1.2px
  • 格子文字:按协议色(见下)

协议主题色(仅用于文字 / 节点框)

协议 主色 标题背景 标题文字
IPIP (4) #7B1FA2 #F3E5F5 #4A148C
TCP (6) #43A047 #E8F5E9 #2E7D32
UDP (17) #FF8F00 #FFF8E1 #E65100
GRE (47) #1565C0 #E3F2FD #0D47A1

函数色(所有协议框统一,不随协议变)

函数 背景 文字
gso_segment #FFF59D(黄) #5D4037(深棕)
gro_receive #1B5E20(深绿) #FFFFFF(白)
gro_complete #1B5E20(深绿) #FFFFFF(白)

4.3. 边框

元素 描边
数组条外框 #333 1.5px
节点框 协议主色 1.5px
节点标题分隔线 协议主色 1.5px
明细虚线框 #90A4AE 1px,stroke-dasharray="4,3"

4.4. 箭头与连线

  • 曲线:<path> 贝塞尔(C 命令),起点在数组格底部中心,终点在节点框顶中心
  • 箭头 marker:
    • viewBox="0 0 10 10"
    • refX="0"(尾部对齐曲线终点,见「箭头对齐」)
    • refY="5"
    • markerWidth="6" markerHeight="6"
    • orient="auto"
    • fill="#000000"(统一黑色)
  • 颜色:连线与箭头统一黑色 #000000,不随协议变色

5. 技术实现要点

5.1. 响应式(无滚动条)

1
2
3
4
5
6
7
8
9
10
11
.svg-container {
width: 100%;
max-width: 1280px;
box-sizing: border-box;
/* 不要设置 overflow: auto */
}
.svg-container svg {
display: block;
width: 100%;
height: auto;
}
1
2
3
<svg xmlns="..." viewBox="0 0 1280 300">
<!-- 不写 width / height 属性 -->
</svg>

5.2. 文字宽度精确控制

问题:浏览器字体渲染的字符宽度和手动估算不一致,导致背景框和文字不贴合。

方案:用 textLength 强制锁定宽度:

1
2
3
<rect x="290" y="288" width="105.6" height="16" fill="#FFF59D"/>
<text x="290" y="296" font-size="11"
textLength="105.6" lengthAdjust="spacingAndGlyphs">tcp4_gso_segment</text>
  • 105.6 = 16 字符 × 6.6px/字符(11px monospace 平均字宽)
  • lengthAdjust="spacingAndGlyphs" 会拉伸字形以适应宽度

5.3. 分组标签的冒号

规则:callbacks、ops、handlers 这类”字段分组标签”后面不加冒号。

1
2
3
4
5
6
7
8
✅ callbacks
gso_segment : tcp4_gso_segment
gro_receive : tcp4_gro_receive
gro_complete : tcp4_gro_complete

❌ callbacks :
gso_segment : tcp4_gso_segment
...

理由:标签是”分组标题”而非键值对;下面三行已经是 字段 : 值 形式,冒号已足够表达关系。

5.4. 顶层声明的粗体

规则:声明行整体正常字重,只对关键标识符加粗。

1
2
3
4
5
<text font-family="monospace" font-size="14" fill="#000000">
<tspan>const struct net_offload __rcu *</tspan>
<tspan font-weight="bold">inet_offloads</tspan>
<tspan>[MAX_INET_PROTOS] __read_mostly;</tspan>
</text>

效果:inet_offloads 明显加粗,其余正常。

5.5. 边框压住背景

错误的绘制顺序(背景会盖住边框):

  1. 主框 rect
  2. 标题栏 rect(有背景色)
  3. 内容

正确的绘制顺序:

  1. 主框 rect(只有 fill,无 stroke)
  2. 标题栏 rect(只有 fill,无 stroke)
  3. 内容
  4. 顶层边框 rect(只有 stroke,无 fill) ← 压在最上层
  5. 标题分隔线

5.6. 箭头对齐

问题:箭头尖端与框顶之间容易留有缝隙。

精确公式:

1
2
箭头长度 = markerWidth × strokeWidth = 6 × 1.8 = 10.8px
曲线终点 y = 框顶 y − 10(向上取整,让尖端略微嵌入 0.8px 消除视觉缝隙)

示例(框顶 y=130):

1
2
3
<!-- 曲线终点 y = 130 - 10 = 120,箭头尖端正好落在 130 -->
<path d="M ... 120" marker-end="url(#arrow-black)"/>
<rect y="130" .../>

5.7. 数组条格子布局

  • 每格固定宽度(本项目用 38px)
  • 第 N 格的左边界 = 起始 x + N × 格宽
  • 第 N 格的中心 = 起始 x + N × 格宽 + 格宽 / 2
  • 有指针的格子:实线边框 + 协议色文字
  • 空槽格子:虚线分隔 + 灰色 ... 标记
  • 末格:写数组长度(如 255)

6. 常见坑与解决方案

# 坑 解决方案
1 页面出现横向滚动条 去掉 overflow: auto,SVG 用 viewBox + width:100%
2 背景色块和文字不贴合 用 textLength 锁定宽度,rect 用同数值
3 框太宽 宽度 = 最长文字宽 + 2 字符
4 节点框宽度不一致 同类节点用同一宽度值
5 箭头和框有空隙 refX=0 + 终点提前到 框顶 - 10.8
6 边框被背景色盖住 最后再画一层 stroke-only 的边框
7 数组格位置对不上 每格固定 38px,下标 × 38 就是格左边界
8 顶部声明文字太占位 去掉外框,只留一行文字,紧贴数组条
9 大量空槽占地方 用一个格子写 ... 代表连续空槽
10 尾部长度无标识 末格写数组长度(如 255)
11 分组标签后带冒号 删除(见「分组标签的冒号」)
12 箭头/连线颜色太花 统一黑色 #000000
13 函数背景色跨协议不统一 按函数类型固定配色(见「配色」)

7. 绘图 Checklist

7.1. 结构层

  • 明确数据结构的本质(数组 / 链表 / 树 / 注册表)
  • 明确”根对象”和”子对象”的关系
  • 确定每个节点的字段(只保留必要的)
  • 确定”排序 / 索引”规则(如 protocol 号)

7.2. 视觉层

  • 主色定义(几个协议几个色)
  • 字体规范(字号、字重、字体族)
  • 边框规范(宽度、颜色、虚实)
  • 背景色规范(只在高亮元素用,不用大面积)
  • 箭头规范(长度、粗细、颜色、对齐)

7.3. 技术层

  • SVG 用 viewBox,不写固定 width / height
  • CSS 用 width:100% + height:auto
  • 关键文字用 textLength 锁定宽度
  • 边框最后画(stroke-only,压上层)
  • 曲线 + marker,refX=0
  • 数组每格等宽,位置 = 索引 × 格宽
  • 箭头尖端与框顶无缝(终点 = 框顶 − 10.8)

7.4. 内容层

  • 无用信息全部删除(如默认值 flags = 0)
  • 分组标签后不加冒号
  • 顶层声明只加粗关键标识符
  • 尾部用 ... + 长度数字
  • 代码区可选,不喧宾夺主
  • 一句话总结放 Subtitle

8. 修改历史归档(可作为需求模板)

按迭代顺序,记录本项目所有修改要求:

8.1. 结构性确认

  • 静态图,不做动画
  • inet_offloads[] 是数组,不是链表(与 offload_base 链表区分)
  • 参考 commit:de27d001d1877(2012 引入)
  • 参考内核版本:6.6+

8.2. 布局

  • 数组条横向排列,不是纵向
  • 每个元素占一格
  • 只保留一行(不要下标行 + 值行两行)
  • 连续空槽用一个格子放 ... 表示
  • 末尾最后一格写 255

8.3. 尺寸

  • 数组格宽度压缩到 20%(最终 38px/格)
  • 结构体框宽度按函数名长度自动调整
  • 同层节点框等宽
  • 框间距一致(33px)
  • 框高 150px,标题栏 28px

8.4. 内容取舍

  • 去掉 flags : 0 行
  • 去掉底部 struct net_offload 定义框
  • 去掉 inet_offloads[] 数组 标题行
  • 去掉 net/ipv4/protocol.c 行
  • 去掉 MAX_INET_PROTOS = 256 说明
  • 去掉”(指针)”等废话标注
  • callbacks 后面不加冒号

8.5. 文字与配色

  • callbacks 字号与函数名一致(11px)
  • 函数名缩进 2 字符
  • 声明行:整体正常字重,只 inet_offloads 加粗
  • 声明行与数组条紧贴
  • 函数背景色:gso_segment 黄,gro_* 深绿(跨协议统一)
  • 背景色与文字等宽(textLength)
  • 边框比最长文字往右多 2 字符

8.6. 数组条风格

  • 外框统一黑色
  • 有指针的格子:实线黑色
  • 空槽格子:虚线灰色
  • 不要彩色背景
  • 不要彩色边框
  • 保留字体颜色(协议色)

8.7. 连线

  • 曲线终点加箭头
  • 箭头尾部对齐曲线终点(refX=0)
  • 箭头尖端接触框顶(不留缝)
  • 框整体下移给箭头留空间
  • 箭头与连线统一黑色

8.8. 内容扩充

  • 增加 IPIP:4 / GRE:47
  • 四个注册点:IPIP / TCP / UDP / GRE
  • IPIP:4 前面只有 0~3 四个空槽
  • 各 protocol 按真实下标就位

9. 快速启动 Prompt 模板

复制以下内容作为新任务的输入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
请按以下规范绘制一张 Linux 内核数据结构 SVG 静态图:

【参考原型】
martinbj2008.github.io/html/fib_animation.html 的视觉风格(无动画)

【数据结构】
- 根对象:<填入>
- 子对象:<填入>
- 关系:<填入,如注册/挂载/索引>

【视觉要求】
1. 顶部:Title(Arial 20px bold #1565C0)+ Subtitle(Arial 12px #666)
2. 声明行:monospace 14px,只对关键标识符加粗
3. 主体:<数组条 / 链表 / 树>,节点等宽,间距均匀
4. 节点框:标题栏 28px + 内容区,配色按协议
5. 分组标签(callbacks 等)后不加冒号
6. 明细字段格式:字段名 + 空格 + : + 空格 + 值
7. 箭头与连线:黑色 #000000,refX=0,尖端无缝接触框顶
8. 数组条:黑框,有值格实线,空槽虚线 + "...",末格写长度

【技术约束】
- SVG 用 viewBox,不写 width/height
- CSS 用 width:100% + height:auto
- 文字宽度用 textLength 锁定
- 边框最后画(stroke-only)
- 页面无滚动条

【参考配色】
- IPIP 紫 #7B1FA2 / TCP 绿 #43A047 / UDP 橙 #FF8F00 / GRE 蓝 #1565C0
- gso_segment 黄底 #FFF59D 棕字 #5D4037
- gro_* 深绿底 #1B5E20 白字 #FFFFFF

【禁止项】
- 不要动画
- 不要 "(指针)" 之类废话
- 不要彩色箭头(统一黑)
- 不要数组条背景色
- 不要分组标签后的冒号

deepseek 总结的html绘图规范
https://martinbj2008.github.io/2026/09/29/html-pic-md/
Author
Martinbj2008
Posted on
September 29, 2026
Licensed under