Hugo相对路径图片显示问题的分析与解决
写博客的时候用 Obsidian 插了张图:
先说问题
写博客的时候用 Obsidian 插了张图:
编辑器里看着好好的,一跑 hugo 部署上去,图裂了。打开浏览器开发者工具一看,图片请求的路径根本就不对。
检查了一圈,发现这个问题只出现在 非 bundle 的 md 文件 上,用目录包起来的 index.md 反倒没事。
为什么会有这个问题
Hugo 的两种页面
Hugo 里写文章有两种姿势:
- Page Bundle — 建个文件夹,里面放
index.md,图片丢同目录下
- Leaf Page — 直接一个
.md文件
我这边的目录结构是这样的:
Blowfish 主题自带的图片渲染逻辑,会先用 $.Page.Resources.GetMatch 去捞图片。Bundle 页面自然能捞到,但 leaf page 压根没有 page resources,捞了个空。最后 fallback 到直接把原始相对路径当 src 输出——这就是问题的起点。
Permalink 让路径更深了一層
我的 permalink 配的是:
假设文件是 content/posts/my-post.md,生成的页面 URL 是 /posts/2026/06/05/my-post/。
Leaf page 里的 ,浏览器会以页面 URL 为基准去解析:
但图片实际在哪?在 content/posts/assets/example.jpg。Hugo 构建的时候会把 content 目录下的非内容文件也发布出去,所以这张图实际是:
问题就是:leaf page 在 URL 里多了好几层目录,但图片的相对路径没跟着变。
怎么修的
方案一:改成 Page Bundle(最推荐)
最省事的做法就是把 leaf page 改成 bundle:
这样 $.Page.Resources.GetMatch 能找到图片,而且 Blowfish 的 responsive 图片优化也会生效。缺点是每个文章都要建目录,已有的存量文章多了有点折腾。
方案二:写个 render hook 兜底(我用的方案)
参考了 Joker 的文章,但里面用的 ../ 补丁只适合单层目录,我的 permalink 太深了不管用。改成了拼绝对路径。
在 layouts/_default/_markup/render-image.html 里覆写了 Blowfish 的图片渲染逻辑:
核心逻辑就几件事:
- 先判断是不是 bundle(看
LogicalName是不是"index.md") - 不是 bundle,而且图片路径是相对路径——就用
.Page.File.Dir拼出内容目录下的绝对路径 - 试着找一下图片资源,找不到就直接用绝对路径当 src
path.Join "posts/" "assets/example.jpg" → posts/assets/example.jpg → /posts/assets/example.jpg
这样不管 permalink 多深,路径都不会偏。
验证
修之前:
修之后:
实际效果:

这张图就是 leaf page 引的,能正常显示说明修好了。
几个需要注意的
- 参考文章的方案不适用于深层 permalink:他直接在相对路径前面加
../,只退一层。本项目的/:year/:month/:day/:slug/叠了四层,必须用绝对路径 - Leaf page 没有图片优化:Page bundle 的图片会被 Blowfish 做 responsive resize(生成多尺寸 + srcset),leaf page 的图不会。如果对图片体积有要求,还是推荐 bundle
- 我这修复只动了 render hook:不影响 bundle 页面,不影响远程图片,不影响已经用了绝对路径的图片
总结
| 维度 | Page Bundle | Leaf Page + render hook |
|---|---|---|
| 图片优化 | ✅ responsive + srcset | ⚠️ 原图直出 |
| 改造成本 | 每篇都要建目录 | 配置一次,存量文章自动修 |
| 适合场景 | 新文章 | 已有大量 leaf page 或者共享 assets 目录 |
新文章我建议直接用 bundle。如果你跟我一样有一堆存量 leaf page 不想动,render hook 兜底一把梭也挺香的。