Markdown 转 HTML 规范
选 sidecar 布局(深色卡片 / 时序 / 时间表 / 胶囊图)前,先读 diagram-style-catalog。本 skill 管 HTML 交卷与 §7.6 深色分层卡片;浅色行动胶囊走 layer-action-capsule-diagram。
目录 • Markdown 转 HTML 规范
将 Markdown 文档转换为可在浏览器中独立打开的 HTML 页面,支持 Mermaid 渲染,并在 Mermaid 表达力不足时自动降级为分层彩色卡片布局。
1. 基本结构
生成的 HTML 必须是单文件、零依赖的独立页面(CDN 引用除外):
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>文档标题</title>
<script src="https://cdn.jsdelivr.net/npm/marked@12.0.2/marked.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mermaid@10.9.1/dist/mermaid.min.js"></script>
<style>/* 内嵌全部样式 */</style>
</head>
<body>
<div id="layout">
<nav id="sidebar"><!-- 自动生成目录 --></nav>
<main><article id="content"></article></main>
</div>
<script>/* Markdown 解析 + Mermaid 初始化 + TOC 生成 */</script>
</body>
</html>
要求:
- 深色主题(GitHub Dark 风格),参考色板见下方"配色体系"
- 左侧固定侧边栏(自动从 h1/h2 生成目录)
- 响应式布局(
@media max-width:900px时侧边栏收起) - Markdown 内容通过
marked.js在客户端解析渲染 - 正文
md-toc目录链接必须能跳转,见 §1.1
1.1 正文目录锚点必须兼容 GitHub slug
.md 正文目录由 md-toc 生成,锚点是 github-slugger(与 VS Code / GitHub 预览一致),例如 [1. 怎么验证](#1-怎么验证)、[2.1 正常情况](#21-正常情况)。侧栏 TOC 仍用 h-1 / h-2-1。
标题必须两套 id 都有,缺 GitHub slug 时正文目录会点了没反应:
<h2 id="h-1"><span id="1-怎么验证"></span>1. 怎么验证</h2>
实现已写入模板,不要改回去:
| 文件 | 作用 |
|---|---|
md2html/templates/anchor.js |
mdGithubSlug / mdHeadingHtml / mdFindHashTarget |
md2html/templates/runtime.js |
heading 渲染与正文 # 点击走上述函数 |
md2html/builder.py |
把 anchor.js 拼在 runtime.js 前面再嵌入页面 |
改这三处后必须跑:
node ~/.cursor/skills/markdown-to-html/tests/test_anchor.js
正文 # 点击:先解析目标,找不到就不要 preventDefault(否则默认锚点也被吞掉)。
2. Mermaid 图表处理
2.1 正常情况
Markdown 中的 ```mermaid 代码块由 mermaid.js 在客户端渲染,无需特殊处理。
源 .md 里的图必须已经是深彩色:HTML 全局 theme:'dark' 不能代替节点 style/classDef。若源图是默认浅色节点,导出页在暗色主题里同样难看。写或改源文档时遵循 markdown-export §5 与 mermaid-flowchart-layout §0。
写图前再读三遍:
- 所有的 Mermaid 图表都使用深彩色配色方案,以便适合在暗色主题环境中查看,同时保持良好的对比度和可读性。
- 所有的 Mermaid 图表都使用深彩色配色方案,以便适合在暗色主题环境中查看,同时保持良好的对比度和可读性。
- 所有的 Mermaid 图表都使用深彩色配色方案,以便适合在暗色主题环境中查看,同时保持良好的对比度和可读性。
2.2 触发降级的条件(必须自动判断)
遇到以下任一情况时,禁止使用 Mermaid,必须改用分层彩色卡片布局:
| 信号 | 说明 |
|---|---|
| 节点 > 15 个 | 单个 Mermaid 代码块中节点数超过 15 |
| 层级 > 4 层 | 架构图存在 4 层以上的纵向分层 |
| 并列 subgraph > 3 | 同一层级有 3 个以上并列 subgraph |
| 节点含多行文本 | 节点内需要标题 + 描述 + 注释等多行信息 |
| 双向/复杂连接 | 层间存在大量双向箭头或交叉连接 |
| 表格/列表嵌套 | 节点内需要展示列表或表格形式的子项 |
判断原则:如果 Mermaid 渲染后可能出现节点重叠、文字截断、箭头交叉、需要横向滚动,就必须降级。
2.3 小流程图不要拉满栏宽
useMaxWidth: true(或 CSS width:100%)会把小 flowchart 拉满正文栏;正方形 viewBox 跟着变成近一屏高,四周大片空白。
HTML 模板(已写入 base.css / anchor.js / runtime.js,不要改回去):
.mermaid svg{
max-width:100% !important;
width:auto !important;
height:auto !important;
display:block;
margin:0 auto;
}
flowchart:{htmlLabels:true,curve:'basis',useMaxWidth:false,nodeSpacing:20,rankSpacing:32,padding:8}
Markdown 源里的小图(预览不走上述 CSS)在 fence 内写:
%%{init: {'theme':'dark','flowchart':{'useMaxWidth':false,'nodeSpacing':16,'rankSpacing':28,'padding':8}}}%%
flowchart TB
禁止 .mermaid svg { max-width: none }。宽架构图仍可靠 overflow-x:auto 横向滚动,不要靠撑满栏宽放大节点。
3. 分层彩色卡片布局规范
当 Mermaid 不适用时,使用纯 HTML/CSS 绘制分层架构图。
3.1 配色体系(深色主题)
:root {
--bg:#0d1117; --panel:#161b22; --panel2:#21262d; --border:#30363d;
--text:#c9d1d9; --muted:#8b949e; --dim:#484f58;
--blue:#58a6ff; --bluebg:#0d2137; --bluetxt:#79c0ff;
--green:#3fb950; --greenbg:#122117; --greentxt:#7ee787; --greenborder:#238636;
--orange:#f0883e; --orangebg:#1a150d; --orangetxt:#ffcc80;
--purple:#a371f7; --purplebg:#1a1428; --purpletxt:#d2a8ff; --purpleborder:#6e40c9;
--red:#f85149; --redbg:#2d1215; --redtxt:#ffa198; --redborder:#da3633;
}
3.2 层级配色分配
每一层使用不同颜色主题,从上到下推荐:
| 层级 | 语义 | 颜色 | border | 背景 | 文字 |
|---|---|---|---|---|---|
| 应用层 | 用户态进程 | 灰 | --dim |
--panel2 |
--muted |
| 库/SDK 层 | 链接库 | 蓝 | --blue |
--bluebg |
--bluetxt |
| 服务层 | Daemon | 橙 | --orange |
--orangebg |
--orangetxt |
| 内核层 | 驱动/模块 | 紫 | --purple |
--purplebg |
--purpletxt |
| 硬件层 | FPGA/芯片 | 灰暗 | --dim |
--panel |
--muted |
| 固件层 | MCU/FW | 橙虚线 | --orange dashed |
--orangebg |
--orangetxt |
| 管理面 | 监控/告警 | 红 | --red |
--redbg |
--redtxt |
| 数据面 | 高速数据通路 | 绿 | --green |
--greenbg |
--greentxt |
如果实际层级语义与上表不匹配,可灵活选择颜色,但必须保持相邻层颜色有明显区分。
3.3 HTML 结构模板
每一层使用 .layer 容器:
<div class="customfig">
<!-- 一层 -->
<div class="layer layer-xxx">
<div class="layer-header">
<span class="layer-label">层级名称</span>
<span class="layer-sub">层级简要说明</span>
</div>
<div class="layer-body">
<span class="node xxx">节点名称<br><span class="note">附注信息</span></span>
<span class="node xxx">节点名称</span>
</div>
</div>
<!-- 层间箭头 -->
<div class="arrow">↓ 通信方式说明 ↓</div>
<!-- 下一层 -->
<div class="layer layer-yyy">
...
</div>
<!-- 图例(可选) -->
<div class="legend">
<div><span class="swatch" style="border-color:var(--blue);background:var(--bluebg)"></span> 库层</div>
<div><span class="swatch" style="border-color:var(--orange);background:var(--orangebg)"></span> 服务层</div>
</div>
</div>
3.4 CSS 基础类
.customfig {
background: #0d1117; border-radius: 12px; padding: 28px; margin: 18px 0;
font-family: "SF Mono","Cascadia Code",monospace; font-size: 13px;
line-height: 1.55; color: var(--text); border: 1px solid var(--border);
}
.layer {
border: 2px solid var(--dim); border-radius: 8px;
padding: 12px 14px; margin: 0 0 4px 0; background: #0d1117;
}
.layer-header {
display: flex; justify-content: space-between;
align-items: center; margin-bottom: 10px; gap: 10px;
}
.layer-label { font-weight: bold; font-size: 14px; }
.layer-sub { color: var(--dim); font-size: 11px; }
.layer-body { display: flex; gap: 6px; flex-wrap: wrap; justify-content: center; }
.node {
padding: 6px 12px; border-radius: 5px; font-size: 12px;
display: inline-block; line-height: 1.4;
}
.node .note { font-size: 10px; opacity: .8; }
.arrow { text-align: center; color: var(--dim); margin: 2px 0; font-size: 11px; }
3.5 复杂布局扩展
当单层内有子分组(如"管理面 vs 数据面"并列)时,使用 flex 分栏:
<div class="layer-split">
<div class="subpanel panel-mgmt">
<div class="panel-header">管理面</div>
<div class="panel-tags"><span>功能项 A</span><span>功能项 B</span></div>
</div>
<div class="panel-bridge">
<span class="bridge-arrow">◄──►</span>
<span class="bridge-label">通信方式</span>
</div>
<div class="subpanel panel-data">
<div class="panel-header">数据面</div>
<div class="panel-tags"><span>功能项 C</span><span>功能项 D</span></div>
</div>
</div>
当需要网格布局(如多列功能矩阵)时,使用 CSS Grid:
.layer-body.grid-4 {
display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px;
}
4. <template> 注入机制
将自绘图放在 <template> 标签中,通过占位符注入 Markdown 渲染结果:
- 在 Markdown 源文本中放置占位符:
<!-- FIGURE: fig-id --> - 在 HTML 的
<template id="fig-id">中定义图形 - JS 渲染完成后,将占位符替换为 template 内容
document.querySelectorAll('[data-figure]').forEach(el => {
const tpl = document.getElementById(el.dataset.figure);
if (tpl) el.replaceWith(tpl.content.cloneNode(true));
});
5. 文件命名
- 与源 Markdown 同名,扩展名改为
.html - 放在与源文件相同的目录下
- 例:
architecture-design.md→architecture-design.html - 工作区根存在
ai.cursor/且正在新建说明文档时,REQUIRED: 先按ai-cursor-doc-output放置源 md,再把 html / sidecar 放在同一知识库子目录;不要单独把.html写到仓库根「方便打开」
6. 不要做的事
- 不要把所有图都降级为卡片——简单的 Mermaid 图保留 Mermaid
- 不要把
.mermaid svg设为max-width:none或默认useMaxWidth:true——小流程图会被拉满栏宽 - 不要使用外部 CSS 文件——所有样式内嵌
- 不要使用外部图片——图表全部用 HTML/CSS 绘制
- 不要生成后不检查——生成后应提醒用户在浏览器中预览确认
- 不要只给标题
id="h-N"、丢掉 GitHub slug——正文目录(#1-怎么验证)会无法跳转;不要从builder.py拿掉anchor.js拼接
7. CLI 工具(md2html)
本技能目录下提供可复用的 Python CLI,Agent 与人工均可调用。
7.1 安装
pip install -e ~/.cursor/skills/markdown-to-html
# 无 pip:~/.cursor/skills/markdown-to-html/bin/md2html build doc.md
7.2 常用命令
见 §7.7 命令速查。工作流见 §7.5 两阶段工作流。
7.3 Sidecar 是什么
Sidecar(边车):与主 Markdown 配套挂载、不写入 .md 正文的 HTML 图稿目录。
doc.md ← 主文档
doc.figures/ ← sidecar 目录
mermaid-0.html ← 替换第 0 个「应降级」的 Mermaid 块
mermaid-1.html
extra.css ← 可选,追加页面样式
md2html build 将 sidecar 合并进单页 HTML 的 <template>,正文通过 customfig:mermaid-N 或 <!-- FIGURE: id --> 引用。
7.4 Sidecar 目录约定
| 规则 | 说明 |
|---|---|
| 默认路径 | 与 doc.md 同级:doc.figures/ |
| Mermaid 替换 | 第 N 个应降级块 → mermaid-N.html(从 0 起) |
| 自定义图 | 任意 fig-id.html,Markdown 用 <!-- FIGURE: fig-id --> |
| extra.css | 追加页面内嵌样式。长表冻结标题行用 freezing-html-table-headers(页面级 sticky,禁止 overflow+max-height 内嵌框) |
| 文件内容 | 片段 HTML(.customfig 根元素);可含 scoped <style> |
| 输出 HTML | 与 doc.md 同目录、doc.html |
7.5 两阶段工作流(推荐)
原则:先批量铺基本 sidecar,再按需精修单张图。 不要一上来就把每张图都打磨到出版级。
阶段 A — 基本 sidecar + 构建(铺底)
适用于:知识库整批转 HTML、新文档首次导出。
分析(单篇或批量)
md2html analyze path/to/doc.md记录:块编号 N、是否建议降级、对应
doc.figures/mermaid-N.html路径。为每个「建议降级」的块写基本 sidecar
- 覆盖原 Mermaid 的节点与层次,结构正确即可。
- 使用 §3 配色 + §7.6 布局模式之一。
- 复杂连线用底部 deps 文字概括,不必画全箭头。
- 暂不追求与旧 Mermaid 像素级一致。
无 Mermaid 或 analyze 未触发降级
- 直接
md2html build,保留客户端 Mermaid 渲染。
- 直接
构建并预览
md2html build path/to/doc.md # 或批量:md2html build docs/*.md提醒用户在浏览器打开
.html通读;列出仍缺 sidecar 的块(若有警告)。阶段 A 完成标准
- 应降级的块均有
mermaid-N.html,构建无「缺少 sidecar」警告。 - 版面可读、无严重重叠;允许文案略简、版式略糙。
- 应降级的块均有
阶段 B — 针对性打磨(按需)
适用于:用户点名某节、某张图「惨不忍睹」或要对外汇报的「推荐图」。
- 只改一个文件:
doc.figures/mermaid-N.html(或具名fig-id.html)。 - 对照同文档中该 Mermaid 代码块 + 相邻正文表格/说明。
- 可参考同库已打磨范例(如
01-platform-overview.figures/mermaid-1.html、01-platform-framework-diagram.figures/mermaid-0.html)。 - 重建单篇:
md2html build path/to/doc.md,浏览器只复查该节。 - 不要为打磨一张图而批量重绘全库 sidecar。
flowchart LR
A[analyze] --> B{应降级?}
B -->|否| C[build 保留 Mermaid]
B -->|是| D[写基本 mermaid-N.html]
D --> E[build + 预览]
E --> F{用户要精修?}
F -->|否| G[完成]
F -->|是| H[只改该 mermaid-N.html]
H --> E
Agent 执行 md 转 html 任务时:默认走阶段 A;仅当用户明确要求或预览反馈某图不合格时,进入阶段 B。
7.6 布局模式速查
阶段 A 优先选用下表,避免每张图从零设计:
| 模式 | 适用场景 | 结构要点 |
|---|---|---|
| platform-stack | L5→L1 软件分层、PPS 职责 | .layer 纵叠 + .arrow + 可选 .deps |
| phys-map | 物理实体 ↔ 软件栈 对照 | 三列:物理 | 映射 | 软件 |
| cfg-data-flow | 配置流 / 数据流 / 同步 并列 | 三列 .lane 纵链 + 跨路 deps |
| multi-stack | 控制器 + 机箱双列 + 分布式 | 见 09/10 计算单元图 |
| link-legend | 仅线型图例 | 五色横条,无架构节点 |
| seq-flow | 简化的时序/步骤 | 水平步骤条(非 Mermaid sequence) |
| seq-swimlane | 多角色 sequenceDiagram、要贴顶角色栏 |
见个人 skill html-sequence-swimlane(sidecar + extra.css) |
7.7 命令速查
# 安装(有 pip)
pip install -e ~/.cursor/skills/markdown-to-html
# 无 pip
~/.cursor/skills/markdown-to-html/bin/md2html build doc.md
md2html analyze doc.md # 阶段 A:清单
md2html build doc.md # 合并 sidecar → HTML
md2html build doc.md --open # 构建并打开浏览器
md2html build doc.md --strict-figures # CI:缺 sidecar 即失败
更多示例见 README.md。