PlantUML 主题包:自制定义主题(CSS / !theme 编译 / 内部发布)

puml.online

PlantUML 自带 20+ 主题,但公司的品牌色 / 暗色模式 / 印刷色没法覆盖——这一篇把”自制主题 + 内部发布”的流程打通。

主题的三种形态

PlantUML 主题支持 4 个层级:

层级 谁用 文件格式
skinparam 单图 / 单 .puml 内联
!theme 文件 单团队 / 多图 .puml 文件
官方皮肤包 PlantUML 自身 内置
CSS / SVG transform 后处理 pipeline

前三者 PlantUML 1.2018+ 支持。CSS 处理属于「render 后再处理」的 pipeline 法。

方案 1:内联 skinparam(最小改动)

直接在每张图顶部加皮肤参数:

1
2
3
4
5
6
7
8
9
10
@startuml
skinparam backgroundColor #FAF9F6
skinparam defaultFontName "Inter"
skinparam shadowing false
skinparam nodesep 50
skinparam ArrowColor #5B7C99
skinparam ArrowThickness 1

Alice -> Bob
@enduml

每张图都重复——繁琐,不适合「公司 30 个工程师」场景。

改良:写一个 skins/standard.puml 文件:

1
2
3
4
5
6
7
!global
skinparam backgroundColor #FAF9F6
skinparam defaultFontName "Inter"
skinparam shadowing false
skinparam nodesep 50
skinparam ArrowColor #5B7C99
skinparam ArrowThickness 1

每张图顶部加:

1
!include skins/standard.puml

比每个图重复一份要省事。但「include 路径」在不同 IDE 下各异(VS Code plantuml.includepaths / 命令行 -I),团队协作依旧痛。

方案 2:!theme 真正的主题包

PlantUUM 1.2018 后引入的 !theme 语法——区别在于「主题资源统一管理」。

结构

1
2
3
4
5
themes/
├── company-brand/
│ ├── puml-theme.css # 配色变量定义
│ ├── puml-theme.puml # skinparam 汇总
│ └── README.md

puml-theme.css(CSS 变量)

1
2
3
4
5
6
7
8
/* 品牌主色:紫罗兰 + 暖灰 */
--brand-primary: #6B5ACD;
--brand-secondary: #5B7C99;
--brand-bg: #FAF9F6;
--brand-text: #1F2937;

/* 字体 */
--font-sans: "Inter", "Noto Sans CJK SC";

puml-theme.puml(PlantUML 语法)

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
!$brand_primary   = "#6B5ACD"
!$brand_secondary = "#5B7C99"
!$brand_bg = "#FAF9F6"
!$brand_text = "#1F2937"
!$font_sans = "Inter, Noto Sans CJK SC"

skinparam backgroundColor $brand_bg
skinparam defaultFontName $font_sans
skinparam ArrowColor $brand_secondary
skinparam ArrowThickness 1
skinparam shadowing false

skinparam activity {
BackgroundColor $brand_primary
BorderColor $brand_secondary
FontColor white
}

skinparam sequence {
LifeLineBorderColor $brand_secondary
ParticipantBorderColor $brand_primary
ParticipantBackgroundColor $brand_bg
ParticipantFontColor $brand_text
ArrowColor $brand_secondary
}

skinparam class {
BackgroundColor $brand_bg
BorderColor $brand_primary
FontColor $brand_text
AttributeFontColor $brand_text
AttributeBackgroundColor transparent
}

发布到内部 npm

1
2
3
4
cd themes/company-brand
npm init -y
# 添加 README.md
npm publish --registry=https://npm.internal.company.com/

或者更轻:发布到内部 git 仓库:

1
2
git remote add internal git@git.internal.company.com:design/plantuml-theme-company.git
git push internal main

团队用法

每张图加:

1
2
@startuml
!theme company-brand

VS Code PlantUML 插件读取 !theme

  • 用户装了 plantuml-theme-company-brand npm 包 → 自动搜索
  • 否则需要 !theme company-brand from <path> 配路径

方案 3:render 后处理(CSS / SVG transform)

PlantUML 渲染完 SVG 后,再通过 SVG transform / CSS 重新染色——适合「plantuml 服务已经用着,但想加公司主题」。

用 sed 替换 SVG color 值

1
2
3
4
plantuml -tsvg diagram.puml
sed -i 's|fill="#FFFFFF"|fill="#FAF9F6"|g' diagram.svg
sed -i 's|stroke="#000000"|stroke="#5B7C99"|g' diagram.svg
sed -i 's|font-family="sans-serif"|font-family="Inter, Noto Sans CJK SC"|g' diagram.svg

粗暴但有效——缺点:

  • 不同 PlantUML 版本 SVG 输出的字段名不一致(”stroke” vs “Stroke”)
  • 不同 diagram type 的 schema 不一样

Python transform(更可靠)

1
2
3
4
5
6
7
8
9
10
11
import re

def company_transform(svg):
# 找 PlantUML 的默认色 → 公司主色
svg = svg.replace('"#FFFFFF"', '"#FAF9F6"')
svg = svg.replace('"#000000"', '"#1F2937"')
svg = svg.replace('"#A80036"', '"#6B5ACD"') # 默认红 → 公司紫
svg = svg.replace('"#0000A0"', '"#5B7C99"') # 默认蓝 → 公司辅助蓝
# 字体
svg = re.sub(r'font-family="([^"]+)"', r'font-family="Inter, Noto Sans CJK SC"', svg)
return svg

放 CI pipeline:

1
2
3
4
5
6
- name: Render PlantUML
run: |
for puml in docs/diagrams/*.puml; do
plantuml -tsvg -o /tmp/svg "$puml"
python scripts/company_transform.py < /tmp/svg/$(basename "$puml" .puml).svg > public/img/diagrams/$(basename "$puml" .puml).svg
done

方案 4:PR 评审时强制主题一致

团队内部只在 .puml 文件里加 !theme company-brand——CI 验证:

1
2
3
4
5
6
7
# 在 pre-commit / GitHub Action 里跑
for puml in $(find docs -name '*.puml'); do
if ! grep -q '^!theme ' "$puml"; then
echo "❌ $puml 缺少 !theme 主题声明"
exit 1
fi
done

不写主题 → CI 失败。需要写规范的图:

1
2
3
4
5
@startuml
!theme company-brand

Alice -> Bob: hi
@enduml

暗模式 / 亮模式 自动切换

PlantUML 默认不会根据系统自动切换,但有几种实现:

方案 A:CSS prefers-color-scheme media query

1
2
3
4
5
6
7
8
/* 在 wiki 主题的 CSS 里 */
.diagram-light { display: block; }
.diagram-dark { display: none; }

@media (prefers-color-scheme: dark) {
.diagram-light { display: none; }
.diagram-dark { display: block; }
}

build 时生成 2 套 SVG(亮 + 暗):

1
2
plantuml -tdefault -tsvg diagram.puml   # 亮
plantuml -tdark -tsvg diagram.puml # 暗

HTML 里:

1
2
<img src="diagram.svg" class="diagram-light" />
<img src="diagram-dark.svg" class="diagram-dark" />

方案 B:JavaScript 切换 class

1
2
3
4
5
document.querySelectorAll('.plantuml-theme-toggle').forEach(el => {
el.addEventListener('click', () => {
document.body.classList.toggle('dark');
});
});

主题包提供:

1
body.dark .diagram { filter: invert(1) hue-rotate(180deg); }

粗暴但有效——SVG 整体反色后主题感 ok,色准丢失一点点。

主题版本管理

发布到 npm 的版本号遵循 semver:

1
2
3
npm version patch   # 修改皮肤参数微调
npm version minor # 新增 skinparam block
npm version major # 重大改动,破坏向后兼容

每张图 !theme company-brand 不锁版本——取最新。如果要锁:

1
!theme company-brand@1.2.3

主题包的高级能力

自定义 !function

主题包可以让 PlantUML 提供新的关键字:

1
2
3
!function $brand_node($name)
!return "rectangle \"==$name\" <<brand>>"
!endfunction

然后团队图里直接:

1
2
3
%brand_node("App1")
%brand_node("App2")
App1 -> App2

自定义 !pragma

1
!pragma company_layout

主题文件里:

1
2
3
4
!procedure company_layout
!pragma layout elk
skinparam ranksep 80
!endprocedure

集成 jsDelivr / CDN

发布到 jsDelivr 公开 CDN:

1
2
3
4
5
6
# GitHub 仓库
git tag v1.0.0
git push --tags

# jsDelivr 自动 css/js 拉取
# https://cdn.jsdelivr.net/gh/your-org/plantuml-theme-company@1.0.0/dist/puml-theme.puml

PlantUML 命令行在线引用:

1
plantuml -tpng -o /tmp -include "https://cdn.jsdelivr.net/..." diagram.puml

落地建议

按团队规模选:

团队规模 推荐方案 理由
1-3 人 内联 skinparam 简单直接
4-20 人 !theme 文件 + 内部 git 易维护,复用度高
20+ 人 npm 包 + 版本锁 易分发,CI 验证一致
多产品多团队 多个主题包 product/theme 隔离

小结

  • PlantUML 的主题从「内联」到「包发布」4 层方案
  • 皮肤参数可变就足以覆盖大多数企业需求——别一上来就做 npm 包
  • CJK 字体始终加 skinparam defaultFontName
  • 团队一致 → CI 验证 → 不写主题就拒绝

下一步

  • 标题: PlantUML 主题包:自制定义主题(CSS / !theme 编译 / 内部发布)
  • 作者: puml.online
  • 创建于 : 2026-07-30 11:08:00
  • 更新于 : 2026-08-14 21:34:29
  • 链接: https://puml.online/blog/plantuml-theme-pack/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。