90、【Ubuntu】【Hugo】搭建私人博客:侧边导航栏(四)

【声明】本博客所有内容均为个人业余时间创作,所述技术案例均来自公开开源项目(如Github,Apache基金会),不涉及任何企业机密或未公开技术,如有侵权请联系删除

背景

上篇 blog
【Ubuntu】【Hugo】搭建私人博客:侧边导航栏(三)

分析了 Flexbox 和 Grid 两种布局方式,并给除了 sidebar-related-posts.html 模板,下面就 sidebar-related-posts.html 继续分析

搭建私人博客

sidebar-related-posts.html 内容如下

go 复制代码
{{ $currentPage := . }}
{{ $relatedPages := slice }}

{{ with $currentPage.GetTerms "categories" }}
  {{ range . }}
    {{ $relatedPages = $relatedPages | union .Pages }}
  {{ end }}
{{ end }}

{{ if $relatedPages }}
<div class="sidebar-related">
  <h4>相关分类文章</h4>
  <ul>
    {{ range first 10 (shuffle (uniq $relatedPages)) }}
      {{ if ne .Permalink $currentPage.Permalink }}
        <li><a href="{{ .Permalink }}">{{ .Title }}</a></li>
      {{ end }}
    {{ end }}
  </ul>
</div>
{{ end }}

第二部分:根据 categories 分类查找相关文章

这里有几个点:

  • GetTerms "categories":获取当前文章所属的所有分类
  • with:Go 模板标准库的控制结构,相当于如果这个值存在且非空,则进入下面的块内
  • range:遍历当前文章的所有分类,比如 ["【Ubuntu】","【Gitlab】"]
  • .Page:获取该分类下的所有文章页面
  • union:Hugo 内置模板函数(非原生 Go 模板语法),可以将当前分类的文章列表合并到 $relatedPages 中,并自动去重,比如假设当前文章同时属于分类 A 和 分类 B,其中,分类 A 有文章 [1,2,3],分类 B 有文章 [3,4,5],那么合并后 $relatedPages = [1,2,3,4,5]

第三部分:渲染相关文章列表(最多10篇,排除自己这篇)

go 复制代码
{{ if $relatedPages }}
<div class="sidebar-related">
  <h4>相关分类文章</h4>
  <ul>

如果找到了相关文章(此时列表非空),才显示侧边栏区域

go 复制代码
 {{ range first 10 (shuffle (uniq $relatedPages)) }}

这行是核心,从右往左看,这里 () 是 Hugo 对管道 | 的等价写法:

  • uniq $relatedPages:去除重复文章,因为多个分类可能包含同一篇文章
  • shuffle (...):随机打乱顺序,避免总是显示最新或最旧的
  • first 10 (...):只取前 10 篇
go 复制代码
{{ if ne .Permalink $currentPage.Permalink }}
  <li><a href="{{ .Permalink }}">{{ .Title }}</a></li>
{{ end }}

这里 ne 表示 no equal 不等于,也就是排除当前文章自己,否则会推荐自己,只负责现时其他文章的标题链接

OK,总结一下,sidebar-related-posts.html 模板的作用就是:基于当前文章的分类,智能推荐一批相关,不重复,不包含自己的其他文章,最多10篇,顺序随机

OK,分析完侧边栏模板,再来看 CSS 布局,下面先直接给出基于前面 blog 介绍的 single.htmlsidebar-related-posts.html 的 CSS 布局

css 复制代码
/* === 仅在文章页限制主容器宽度 === */
body .main:has(.post-with-sidebar) {
  max-width: 1920px !important;
  margin: 0 auto !important; /* 居中 */
}

/* === 双栏布局:确保 .post-with-sidebar 占满可用宽度 === */
.post-with-sidebar {
  display: flex !important;
  flex-direction: row !important;
  gap: 2rem !important;
}

.post-with-sidebar .sidebar-related {
  width: 300px !important;
  flex-shrink: 0 !important;
  position: sticky !important;
  top: calc(var(--header-height, 80px) + 1rem) !important;
  height: calc(100vh - var(--header-height, 80px) - 2rem) !important;
  overflow-y: auto !important;
  padding-right: 1rem !important;
  border-right: 1px solid var(--border-color, #eee) !important;
  background: var(--theme-bg, #fff) !important;
  box-sizing: border-box !important;
  margin-top: 3rem !important;
  margin-bottom: 2rem !important;
}

.post-with-sidebar .sidebar-related,
.post-with-sidebar .sidebar-related *,
.post-with-sidebar .sidebar-related a {
  font-size: 1rem !important;
  line-height: 1.5 !important;
  color: var(--text-color-secondary, #666) !important;
}

.post-with-sidebar .post-single {
  flex: 1 !important;
  max-width: 720px !important;
  min-width: 400px !important;
  margin-top: 3rem !important;
  margin-bottom: 2rem !important;
}

/* === 移动端适配 === */
@media (max-width: 768px) {
  .post-with-sidebar {
    flex-direction: column !important;
  }
  .post-with-sidebar .sidebar-related {
    height: auto !important;
    position: static !important;
    border-right: none !important;
    border-bottom: 1px solid var(--border-color, #eee) !important;
    padding-bottom: 1rem !important;
    margin-bottom: 1.5rem !important;
  }
}

/* === 强制修复文章顶部间距 === */
.post-with-sidebar .post-single {
  margin-top: 3rem !important; /* 增大顶部间距 */
  margin-bottom: 2rem !important;
}

OK,再来详细分析下这里的布局

body .main:has(.post-with-sidebar):表示选中 <body> 下的 .main 元素,前提是 .main 的内部要包含一个 class 为 .post-with-sidebar 的子元素,这里的 :has() 是 CSS 父选择器(新特性,现代浏览器支持,但旧版比如 IE 不支持)

比如这里编译后,可以看到 <body> 中的 .main 元素里包含了 .post-with-sidebar

这个特点和 single.html 里面定义的结构是一样的,.main 包含 .post-with-sidebar.post-with-sidebar 再包含 sidebar-related-posts.htmlarticle

这个包含 .post-with-sidebar 条件的意义在于,这个 CSS 样式布局,只针对 single.html,也就是文章内容,才有双栏布局,比如下面其他页面,比如分类页面,是没有 .post-with-sidebar 的,也就不需要双栏布局

然后是设置 .main 样式(双栏布局)的 CSS 样式

  • max-width: 1920px: 最大宽度不超过 1920 像素(一般显示器分辨率是 1920x1080)

  • margin: 0 auto:水平居中,左右 margin 自动

  • !important:强制覆盖其他可能存在的样式,如果发生插件冲突时优先选择这个 CSS 样式

这样整体效果可以让文章页的内容区域不会太宽(提升阅读体验),居中对齐,就和原来的单栏布局差不多


OK,本篇先到这里,如有疑问,欢迎评论区留言讨论,祝各位功力大涨,技术更上一层楼!!!更多内容见下篇 blog
【Ubuntu】【Hugo】搭建私人博客:侧边导航栏(五)

相关推荐
回忆是昨天里的海16 小时前
dockerfile-镜像分层机制
linux·运维·服务器
2501_9419820516 小时前
基于自动化协议的企微外部群消息调度与状态回执实现逻辑
运维·自动化·企业微信
双层吉士憨包17 小时前
如何安全访问 Kickass Torrents:代理选择、设置与最佳实践(2026)
运维·服务器
JY.yuyu17 小时前
Windows Server服务器数据备份 / 活动目录(AD域)
运维·服务器
三翼鸟数字化技术团队17 小时前
搭建自己的MCP服务器
运维·服务器·人工智能
Zsr102317 小时前
Rancher:一站式Kubernetes管理平台,让容器运维更简单
运维·kubernetes·rancher
叽里咕噜怪17 小时前
Rancher
运维·rancher
小五传输17 小时前
认准好用的跨网文件安全交换系统:安全传输与高效协作两全其美
大数据·运维·安全
chen_mangoo17 小时前
Rockchip debian预置安装deb包
linux·驱动开发·嵌入式硬件