迁移 report 到 uv 管理依赖并修复 MkDocs footer 黑栏对齐¶
日期: 2026-05-17 目标: 把 report 仓库从无依赖声明的 pip 安装方式迁移到 uv 管理(锁版本、本地/CI 一致),同时修复 Material 主题底部 Built/Commit 信息独立于黑栏的视觉问题。
背景¶
report 仓库是基于 mkdocs-material 的纯文档站,用 GitHub Actions 自动部署到 Cloudflare Pages(参考早前的 archive-202605011405-report-cloudflare-pages.md)。本次有两个并行问题:
- 前端缺陷:用户曾在
overrides/main.html自行追加了一段<div>用于显示Built: {time} | Commit: {sha},但它落在 Material 默认黑色md-footer-meta栏的下方(作为独立的灰色条带),视觉上让黑栏变得很孤立。 - 环境缺陷:仓库根目录没有
requirements.txt/pyproject.toml。CI 用一行硬编码pip install mkdocs-material安装;新 clone 的人不知道要装什么。本机环境是 anaconda3 Python 3.13,用户希望换 uv 管理,但要求: - 不污染全机器(项目隔离 venv)
- 锁定版本(本地与 CI 完全一致)
- 指令跨系统通用(Windows / macOS / Linux)
- 本机已装 uv(0.10.11),不要重复安装
操作步骤¶
1. 初始勘察¶
读取关键文件:
mkdocs.yml:确认custom_dir: overrides,theme.name: material,extra.generator: falseoverrides/main.html:原始 footer override 是{{ super() }}后追加一个<div>—— 这就是它落在黑栏外的根因.github/workflows/deploy.yml:CI 用actions/setup-python@v5(3.11) +pip install mkdocs-material,并通过python3 << 'PYEOF'注入build_time/git_sha到mkdocs.yml的extra:块- 没有
requirements.txt、pyproject.toml、uv.lock、Pipfile
2. 第一轮 footer 修复(JS 注入,但留下了对齐问题)¶
把 overrides/main.html 从"append div"改为"用 JS 把 div 注入到 .md-footer-meta__inner 内部":
<script>
(function () {
var inner = document.querySelector('.md-footer-meta__inner');
if (!inner) return;
var info = document.createElement('div');
info.className = 'md-footer-build-info';
info.innerHTML = 'Built: ... | Commit: <a href="...">...</a>';
inner.appendChild(info);
})();
</script>
配套 CSS 初版:flex: 1 1 100% + flex-wrap: wrap。这一版让 build-info 进了黑栏,但占满 100% 宽度 → 它独占新一行,跟 GitHub 图标不在同一行。
3. UV 环境搭建¶
第一次跑
uv init --bare --python 3.11 --vcs none在 PowerShell 下报Exit code 1,但没有 stderr 输出。换 bash 重跑:推测是 PowerShell 流处理问题,不是 uv 本身。
pyproject.toml已成功生成(requires-python = ">=3.11",没有创建.python-version,对跨版本兼容更友好)。
uv add mkdocs-material 拉取 29 个包并生成 uv.lock,关键依赖:mkdocs==1.6.1、mkdocs-material==9.7.6。uv run mkdocs --version 验证可用。
期间有一条无害 warning:
warning: `VIRTUAL_ENV=...\python\cpython-3.12.13-windows-x86_64-none` does not match the project environment path `.venv` and will be ignored
.venv,不需处理。
4. 同步周边文件(并行编辑)¶
.gitignore:在# Python区段末尾追加.venv/(注意保留uv.lock不被 ignore,必须提交).github/workflows/deploy.yml:actions/setup-python@v5→astral-sh/setup-uv@v4,pinversion: "0.10.11"对齐本地pip install mkdocs-material→uv sync --frozenpython3 << 'PYEOF'→uv run python << 'PYEOF'(注入 build_time/git_sha 的脚本本体不变)mkdocs build→uv run mkdocs buildREADME.md:新增"🛠️ 本地开发"段落,给出 Windows (irm | iex) 和 Unix (curl | sh) 两套 uv 安装命令,统一开发流程为uv sync+uv run mkdocs serve
5. 第二轮 footer 修复(横向同行)¶
把 CSS 改为:
JS 改用 insertBefore(info, social) 而不是 appendChild,让 build-info 落在 GitHub 图标左侧——视觉顺序变成 [空 copyright] [Built/Commit 居中] [GitHub 图标右对齐]。
6. 第三轮 footer 修复(垂直对齐)¶
用户截图反馈:build-info 跟 GitHub 图标横向同行了,但纵向不齐(build-info 偏上、GitHub 图标偏下)。
直接 curl 抓 Material 的 main CSS 看实际规则:
curl -s http://127.0.0.1:8000/assets/stylesheets/main.484c7ddc.min.css \
| grep -oE '\.md-footer-meta__inner\{[^}]*\}|\.md-social\{[^}]*\}|\.md-copyright\{[^}]*\}'
结果:
.md-footer-meta__inner { display:flex; flex-wrap:wrap; justify-content:space-between; padding:.2rem }
.md-copyright { color:var(--md-footer-fg-color--lighter); font-size:.64rem; margin:auto .6rem; padding:.4rem 0; width:100% }
.md-copyright { width:auto }
.md-social { display:inline-flex; gap:.2rem; margin:0 .4rem; padding:.2rem 0 .6rem }
.md-social { padding:.6rem 0 }
定位根因:
- .md-footer-meta__inner 没有 align-items,默认是 stretch —— 子元素会被拉伸到容器高度
- .md-copyright 通过 margin: auto .6rem 用 auto-margin 做垂直居中
- .md-social 用 padding: .6rem 0 把图标推到自己 box 的中心
- 我的 .md-footer-build-info 没用这两个技巧,所以被 stretch 后内容靠顶
修法:直接套用 .md-copyright 的 DNA(margin: auto .6rem + padding: .4rem 0 + 同样的 font-size: .64rem)。最终 CSS:
.md-footer-build-info {
flex: 1 1 auto;
text-align: center;
margin: auto 0.6rem;
padding: 0.4rem 0;
font-size: 0.64rem;
color: var(--md-footer-fg-color--lighter);
}
.md-footer-build-info a {
color: inherit;
text-decoration: underline;
}
用户重启 serve 后确认成功。
7. 验证 & 提交¶
uv run mkdocs build --clean 通过(1.79s),证明 uv 管道闭环。
提交 SHA 596df89,6 个文件 (+622 / −10),包含新增的 pyproject.toml 和 uv.lock。
遇到的问题与解决¶
问题 1:PowerShell 下 uv init 静默失败¶
现象: uv init --bare --python 3.11 --vcs none 在 PowerShell 返回 Exit code 1 但无 stderr 输出。
原因: 推测是 PowerShell 对 stderr/stdout 流的处理问题,跟 uv 本身无关。
解决: 直接在 bash 下重跑,正常输出 Initialized project 'report'。后续 uv 命令两边都能跑(uv 跨 shell 兼容),只是初次 init 在 PowerShell 下踩了一脚。
问题 2:mkdocs serve 不热重载 overrides/ 改动¶
现象: 修改 overrides/main.html 后等了 56 秒,curl http://127.0.0.1:8000/ 仍返回旧 CSS。文件 mtime 早于当前时间。
原因: 实测 mkdocs serve 对 theme.custom_dir 不可靠地监听(文档说应监视,实际未触发)。
解决: 必须手动 Ctrl+C 重启 serve。新增依赖、改 mkdocs.yml 时一般会重载,但改 overrides/ 模板不会。
问题 3:第一次 footer 修复后视觉跑到了黑栏外¶
现象: JS 注入应该把元素放进 .md-footer-meta__inner,但用户截图显示 Built/Commit 像是在黑栏之外(黑文本/浅背景)。
原因(最终判定): 用户当时的浏览器没刷新到最新版(mkdocs serve 没重载,curl 也证实服务端仍是旧版)。一旦 serve 重启,元素就在黑栏内了。
教训: 在调试 overrides 时,永远先确认 curl <url> | grep <my-class> 拿到的是最新版本再判断 CSS 问题。
问题 4:横向同行后纵向偏移¶
现象: build-info 居中显示在黑栏顶部,GitHub 图标在黑栏底部,纵向不齐。
原因: Material 的 .md-footer-meta__inner 没有 align-items,默认 stretch;不同子元素用了不同的垂直居中技巧(copyright 用 margin: auto,social 用对称 padding),自定义元素若都不用就靠顶。
解决: 套用 .md-copyright 完整的样式 DNA(margin + padding + font-size),让自定义元素行为等价于"一个有内容的 copyright"。
知识清单¶
Material for MkDocs footer 内部结构(v9.7.6)¶
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright"> ... </div> <!-- 空时也会渲染容器 -->
<div class="md-social"> ... </div> <!-- 包含 social.icons -->
</div>
</div>
</footer>
.md-footer-meta整个是黑栏(暗色背景由 theme 控制).md-footer-meta__inner是display: flex; flex-wrap: wrap; justify-content: space-between,没有align-items- 想"塞进黑栏"必须 append/insert 到
.md-footer-meta__inner内部 - 垂直居中:套用
.md-copyright的margin: auto .6rem+padding: .4rem 0
uv 项目初始化模式(文档站场景)¶
uv init --bare --python 3.11 --vcs none # bare = 无 README/sample,vcs none = 不动 git
uv add mkdocs-material # 装 + 锁定 + 同步 .venv
uv run mkdocs serve # 后续所有命令前缀 uv run
--python 3.11只写入requires-python = ">=3.11",不生成.python-version,本地装的 3.13 也能用- 强烈建议
uv.lock入库;CI 用uv sync --frozen拿到 bit-exact 的依赖 - 跨平台(Windows/macOS/Linux)uv CLI 完全一致
deploy.yml 从 pip 改 uv 的最小 diff¶
- - name: Setup Python
- uses: actions/setup-python@v5
- with:
- python-version: '3.11'
- - name: Install dependencies
- run: pip install mkdocs-material
+ - name: Setup uv
+ uses: astral-sh/setup-uv@v4
+ with:
+ version: "0.10.11"
+ enable-cache: true
+ - name: Install dependencies
+ run: uv sync --frozen
...
- python3 << 'PYEOF'
+ uv run python << 'PYEOF'
...
- - name: Build site
- run: mkdocs build
+ - name: Build site
+ run: uv run mkdocs build
enable-cache: true 让 setup-uv 把下载缓存到 Actions cache。
Flexbox auto-margin 垂直居中¶
在 flex 容器里给子元素 margin: auto 会吃掉所有剩余的主轴/交叉轴空间并均分到上下/左右,等效于双向居中。比 align-items: center 更精确(针对单个子元素,不影响其他)。Material 在 footer 里就是这么实现的。
curl 调试已 serve 的 mkdocs 站¶
# 抓 CSS bundle 路径
curl -s http://127.0.0.1:8000/ | grep -oE 'href="[^"]*\.css"'
# 抓某个 selector 的实际规则
curl -s http://127.0.0.1:8000/<css-url> | grep -oE '\.classname\{[^}]*\}'
# 验证自定义 JS 注入是否到达浏览器
curl -s http://127.0.0.1:8000/ | grep -c 'my-marker-class'
待办 / 遗留¶
- [ ] mkdocs build 输出大量
monitor-system/*文档里的失效相对链接(指向main.py、swellcamera/*.py等不在文档树里的代码文件)。本次没动,预计后续单开一轮清理。 - [ ] 文档相对链接锚点 mojibake:部分
#章节-X锚点匹配失败(涉及 hermes-session、monitor-system),可能是 mkdocs 对中文锚点的归一化策略差异,需要单独排查。 - [ ]
setup-uv@v4的版本是从经验选的,未来发布新主版本时需要看是否要升级;同样 uv 本身 pin 在 0.10.11,跟随本机版本,不一定永远是最新。