导航与菜单
OINK 把 Hugo 的内容树和菜单模型组织成一套文档工作台:出现在所有布局上的站点导航栏、可折叠且可调整宽度的分区侧边栏、位于右栏的可折叠页面大纲,以及站点页脚。同一套结构适用于英文、中文和从右向左书写的语言。
站点导航栏
导航栏由 Hugo 的 main
菜单与 OINK 自动生成的控件组成:版本选择器、语言选择器、颜色模式控件、搜索,以及项目仓库链接。它会在所有布局上渲染——落地页、文档、博客、Swagger 和分类页面都不例外,因此站点级导航在任何位置都只有一次点击的距离。
关闭导航栏
navbar_enabled 默认为 true。可以对整个站点关闭导航栏,也可以通过 front
matter(前置元数据)cascade 对某个分区关闭,或只对单个页面关闭:
Front matter 的优先级高于站点参数,而且显式写出的 false
在任何层级都会生效。关闭导航栏后,OINK 会恢复此前被导航栏取代的界面:移动端子导航、侧边栏的品牌与搜索行、目录轨道上的工具按钮,以及侧边栏底部的工具区。这个开关适用于必须独占整个视口的页面,不应当作常规排版偏好使用。
两种状态,没有独立的移动菜单
导航栏只有两种状态:
| 宽度 | 状态 |
|---|---|
lg 及以上 |
完整:品牌、菜单文字标签与各个工具控件 |
小于 lg |
紧凑:先是 Logo,其余条目全部右对齐为图标 |
紧凑状态并不是精简过的菜单。菜单项保留各自的图标,搜索仍是放大镜,版本、语言与主题控件也停在原处——没有任何东西会折叠进汉堡按钮,因为根本不存在独立的移动菜单。唯一按宽度切换的控件出现在带侧边栏的页面上:小于
md 时会多出一个图标,用于打开侧边栏抽屉。
navbar_accordion_single_open已废弃。该参数会被忽略,请从现有配置中删除。
添加 main 菜单项
可以在页面 Front Matter 中定义菜单项:
权重越小,位置越靠前。站点级外部链接写法类似:
需要在配置中引用菜单项时,应为其设置 identifier。name 或 linkTitle
可以按语言翻译,但标识符必须稳定。
嵌套下拉菜单
顶层菜单支持一级下拉。用 Hugo 的 parent 建立父子关系:
子项的 params.description 会显示在下拉项的标题下方,帮助读者判断该去哪。
交互上有一个关键设计:父级本身就是一个普通链接。悬停或键盘聚焦时展开面板,点击或按 Enter 则直接跳转到父级页面。这里没有单独的展开箭头,父级页面也不会被自己的下拉「劫持」。Esc 关闭面板并把焦点留在链接上;触屏读者会直接进入父级页面,那里的正文同样列出了这些链接。
版本菜单
配置 params.versions
后会显示版本选择器。它是一个分支图标,悬停或键盘聚焦时展开列表,与语言、主题控件共用同一套浮层样式。条目可以表示标题、分隔线、正式版本、开发版本或站点变体:
version
标识已发布的站点变体,不一定是 Git 引用。安装命令等必须使用可解析标签的内容,应改用项目显式定义的发布引用参数。启用页面链接后,OINK 会先尝试目标版本中的同一路径,找不到时再使用条目配置的 URL。
语言菜单
OINK 根据 Hugo 的 AllTranslations
构造语言目标。当前页面缺少某种语言译文时,会链接到该语言首页,而不是生成损坏的 URL。只配置一种语言时不显示控件;配置两种或更多语言时,点击语言图标会按
weight
顺序切换到下一种语言,悬停半秒或聚焦控件则打开完整菜单。当前站点按英文、简体中文的顺序循环。目标链接包含
lang、hreflang、locale 与文字方向属性。
浅色/深色主题菜单
启用颜色模式后,导航栏会显示主题控件。点击它在浅色与深色之间切换,悬停或聚焦则展开「跟随系统 / 浅色 / 深色」三项选择器,其中「跟随系统」采用读者操作系统的设置。详见浅色/深色模式菜单。
搜索框
搜索是导航栏上的一个放大镜图标,点击后打开命令面板;Cmd/Ctrl-K
以及在可编辑控件之外按下的 /
同样可以打开它。启用离线搜索后该图标才会出现;关闭导航栏时,搜索行会回到侧边栏顶部。在线搜索集成仍可通过显式配置启用。详见搜索。
为导航栏添加图标
在菜单项中使用 pre 或 post。OINK 已在本地提供免费版 Font Awesome 资源:
装饰性图标需要设置
aria-hidden="true";链接本身必须保留有意义的文字或无障碍标签。在新标签页打开的外部链接必须使用
rel="noopener"。
小于 lg 时,图标就是菜单项仅剩的表现形式,因此每个顶层菜单项都应配置 pre
图标。没有图标的菜单项在紧凑状态下无内容可显示。
侧边导航
文档页与博客页的左侧面板由内容层级自动生成。OINK 按 weight 排序,并在存在
linkTitle 时用它作为标签。分区来自 _index.md;翻译后的分区需要配套
_index.zh.md,才能正确本地化导航元数据。
从侧边栏隐藏页面:
从分区落地页摘要中隐藏页面则使用
hide_summary: true。只有页面确实不应出现在这两个发现入口中时,才同时设置二者。
侧边导航选项
常用控制项如下:
sidebar_menu_compact只显示当前分支和附近条目;sidebar_menu_foldable允许读者展开或折叠分区。博客栏目默认展开,在栏目 front matter 中设置sidebar_expanded: false可让它默认收起;sidebar_menu_truncate限制条目数,数值过小时会发出构建警告;sidebar_cache_limit在站点规模超过阈值后启用共享导航标记;sidebar_width_min与sidebar_width_max限制桌面端拖拽调整的宽度;sidebar_item_overflow默认为ellipsis,长标签需要换行时改用wrap。
折叠状态、宽度和滚动位置保存在读者本地。移动端会转换为带遮罩层和安全焦点控件的可关闭抽屉。
为侧边导航添加图标
在页面 Front Matter 中设置 icon:
同级条目的图标用法应保持一致。图标只是辅助线索,不能取代文字标签。
侧栏图标密度
叶子页面全都带图标会产生明显的视觉噪声。用 sidebar_icon_policy 控制密度:
| 取值 | 效果 |
|---|---|
all |
每个有图标的侧栏条目都显示 |
groups |
只有根节点和带子页的节点显示图标,普通叶子页不显示 |
none |
侧栏完全不显示条目图标 |
未设置时的兼容默认值是 all。新站点建议显式设为
groups——保留了分组的语义标识,同时去掉叶子层的噪声。本站就用这个设置。
无效取值会产生警告并回退到 all。
为侧边导航添加手动链接
在所需位置创建占位页面:
内部内容引用应使用 manualLinkRelref 而不是
manualLink;Hugo 无法解析目标时会令构建失败。OINK 会为新标签页链接补充
noopener。由于 Hugo 仍会为占位文件生成页面,正文应简短说明实际去向。
将分区设为侧边栏根节点
侧边栏树以读者当前所在的顶层分区为根,树上方那一行标出的就是这个根节点。规模较大的子树——带版本的 API 参考、独立的手册——可以自己成为一个根节点,让读者不必离开当前分区就能切换过去:
然后在后代分区的 _index.md 中设置:
self 会把该根节点应用于分区索引及其后代;children
会把索引留在父级树中,只限制其后代。根分区可以嵌套,但冗余或无效取值会触发构建警告。
切换器的范围限定在当前顶层分区之内:条目是该分区本身(默认项),加上每个设置了
sidebar_root_for: self
的后代分区。同级的其他顶层分区不会列出——在文档与博客之间跳转是导航栏的职责。因此,没有可切换后代的分区根本不显示下拉框,那一行只是一个指向分区落地页的普通链接,没有边框,与树的顶层条目对齐。
分类术语页没有内容层级,因此术语会采用其成员共同所属的顶层分区。从文档页面点进某个标签后,侧边栏保留的仍是文档树和文档根链接,而不会回退到站点级的树;成员横跨多个分区的术语则不显示根节点行。
页面目录
Hugo 根据 Markdown 标题生成右侧页面大纲。OINK 把它渲染为固定右栏中的第一个分组,后面依次排列当前分区的分类标签云。读者可以折叠整个右栏,状态保存在本地。
由 Markdown 短代码({{% ... %}})输出的标题会进入 Hugo 目录;仅由标准短代码({{< ... >}})输出的标题通常不会进入。因此,只要条件允许,内容结构都应保留在 Markdown 中。
目录定制
在单个页面隐藏大纲:
配置 Hugo 收录的标题层级:
toc_on_this_page
等标签在站点 i18n 资源包中翻译。自定义 CSS 调整大纲轨道或固定面板尺寸后,需要测试活动项跟踪、缩放、键盘焦点,以及完全没有标题的页面。
右栏分组
右栏里的每个分组都使用同一套标题行:图标、标题和折叠箭头,整行作为一个条目高亮。大纲分组的标题是「目录」,它的图标是一个三横线字形,作用是折叠整个右栏,而不只是装饰。在侧边栏抽屉中,该分组保留静态的三横线图标,从而与旁边的分类标题保持一致。
分类分组的图标可以按分类复数名配置:
categories 默认使用文件夹图标,tags
默认使用标签图标;其他分类在这里指定之前,一律使用通用的形状图标。标签云本身的范围规则参见分类法支持。
使用 ScrollSpy 跟踪目录活动项
OINK 使用本地 Bootstrap ScrollSpy 补丁与 IntersectionObserver 跟踪活动标题。工作台会绘制连续轨道、活动区段和位置标记。为某个页面关闭跟踪:
旧版 ScrollSpy 配置也接受全局
rootMargin。它会改变条目进入活动状态的时机,应在短分区、长分区和直接片段导航中分别测试。
ScrollSpy 高级定制
优先使用配置与项目 CSS。覆盖 ScrollSpy 属性 Partial 或 docs-shell.js
会形成实现级分支;必须增加浏览器 Fixture,覆盖哈希更新、前进/后退导航、尺寸变化、减少动态效果模式,以及存在重复或缺失 ID 的页面。
面包屑导航
普通内容页上方和分类结果中会显示面包屑,这一行同时承载页面操作。顶层分区页面保留只有一级的面包屑,使这一行在任何层级都保持稳定。全局关闭面包屑的方式如下:
页面或分区 cascade 也可以设置
ui.breadcrumb_disable。面包屑标签来自本地化页面标题,而且必须与侧边栏遵循同一逻辑层级。
页面操作
页面操作是面包屑行末尾的一个纯图标拆分按钮。左半边复制本页 Markdown,成功后翻转为绿色对勾;右侧箭头展开一个包含十项操作的菜单,分为两组。上半组负责把页面内容带到别处:
- 复制 Markdown 文本
- 在 ChatGPT 中打开
- 在 Claude 中打开
- 查阅 Markdown 源码
- 查阅编辑历史
其后是一条分隔线,下半组负责修改或产出内容:
- 编辑本页
- 创建子页面
- 提交文档 issue
- 提交项目 issue
- 打印整个分区
配置的 page_context_menu.links
排在最后,前面还有一条分隔线。每个条目只有在能解析出目标时才出现:Markdown 相关操作需要
markdown 输出格式,仓库相关操作需要 github_repo,项目 issue 需要
github_project_repo,助手操作则需要
params.ui.page_context_menu.assistant_links。
在博客根分区及其一级子分区上,左半边变成 RSS 链接,菜单中仍保留「复制 Markdown 文本」。博客叶子页面不显示订阅图标。没有 Markdown 输出的页面会去掉左半边,改为渲染带文字的「操作」按钮。
create_child_page、create_project_issue 与 print_section
现在都是注册表中的一等操作,因此也会出现在命令面板中。页面级的
print 操作已废弃,读者直接使用浏览器自带的 Cmd/Ctrl+P。
站点页脚
页脚会在所有布局上渲染,由 footer_style 在三种形态之间选择:
| 取值 | 渲染内容 |
|---|---|
fat |
版权行之上的多列网格(默认值) |
slim |
只有版权行 |
none |
完全不渲染页脚 |
Front matter(包含分区 cascade)的优先级高于站点取值:
无法识别的取值会令构建失败,而不是静默回退。
胖页脚数据
多列网格读取 data/footer/<语言>.yaml;单语言站点可以直接使用
data/footer.yaml:
brand.name 与 brand.logo
未设置时回退到站点自身的品牌名、Logo 和 wordmark。tagline 和 slogan
会渲染 Markdown。站内 url 以语言根为基准解析;external: true
会在新标签页打开链接并附带
rel="noopener noreferrer"。网格的列数由数据中的列数决定。
没有数据的 fat 页脚会降级为
slim,因此站点可以先保留默认值,再逐步补齐各列内容。
data/home/<语言>.yaml 中的 footer块仍会作为回退读取。它此前只在首页渲染,现在会应用到全站,因此在继续使用这个旧位置之前,请确认这些链接列从文档深层页面看仍然合理。
标题自链接
使用方站点可以启用 OINK 标题渲染钩子:
生成的 .td-heading-self-link 控件默认使用
#。它在触控设备上始终可见,在指针设备上则于悬停或聚焦时出现。链接必须支持键盘访问,并保留足以避开固定导航的滚动偏移。
标题别名与页内目标
修改标题可能破坏外部片段链接,因此标题 ID 应按公开路由对待。需要重命名 ID 时,应保留旧 ID 的空锚点,并显式写入新 ID:
别名和其他页内目标应使用空的 <a id="..."></a>。不要仅为片段目标使用
span。ID 必须唯一、稳定,在可行时使用 ASCII,并在各语言版本中保持一致。
快速开始
这个真实标题演示了 #get-started 与 #quickstart
都能到达同一位置。译文标题应显式写入英文页面渲染后的 ID,不要依赖不同语言各自生成的自动 slug。
实现说明
- 文档为固定界面设置全局滚动偏移;
- 内置块目标使用
td-anchor-no-extra-offset,避免重复应用额外偏移; - 翻译审计会比较英文与中文页面渲染后的标题 ID;
- 删除旧别名属于破坏性文档变更,需要重定向或明确记录兼容性决策。