首页
/ mkdocs-material 内容标签页(Content Tabs)完整指南:配置、锚点链接与全站联动

mkdocs-material 内容标签页(Content Tabs)完整指南:配置、锚点链接与全站联动

2026-09-10 19:35:29作者:薛曦旖Francesca

本文以 mkdocs-material 的 docs/reference/content-tabs.md 为核心,系统讲解内容标签页(Content Tabs)的启用方式、Markdown 语法、锚点链接与联动切换特性,并结合仓库源码剖析其底层实现原理。读完本文,你将能够在自己的 MkDocs 站点中把代码块、列表乃至任意内容分组到标签页下,实现"一种主题、多语言/多环境切换展示"的文档体验,并掌握可分享锚点与全站联动等高阶用法。

什么时候需要内容标签页

在编写技术文档时,经常遇到"同一份 API 需要给出多种语言或环境下的调用示例""同一配置需要同时展示不同平台的命令"这类场景。逐一罗列会让页面冗长,而内容标签页可以把这些互斥的替代内容收纳进同一个紧凑的组件中——默认只展示一个标签页,用户点击即可切换,其他内容保持折叠。

Material for MkDocs 借助 Python Markdown 扩展 [pymdownx.tabbed] 实现内容标签页,配合 [pymdownx.superfences] 后,标签页内不仅可以放代码块,还可以嵌套列表、告警块(admonitions)、引用块,甚至再嵌套一层内容标签页。从源码结构看,该功能对应的前端组件位于 src/templates/assets/javascripts/components/content/tabs/index.ts,样式定义在 src/templates/assets/stylesheets/main/extensions/pymdownx/_tabbed.scss

快速上手:在 mkdocs.yml 中启用

依赖 SuperFences 与 Tabbed

内容标签页由 pymdownx.tabbed 扩展提供,而要支持"任意内容嵌套",则必须同时启用 pymdownx.superfences。在原文档的推荐配置中,两者缺一不可:

markdown_extensions:
  - pymdownx.superfences
  - pymdownx.tabbed:
      alternate_style: true

其中 alternate_style: true 是 Material for MkDocs 唯一官方支持的标签页样式,它在移动端视口下有更好的表现(标签可横向滚动、不会挤压内容区域)。该选项在扩展的官方配置说明中被标记为"必需",详见 docs/setup/extensions/python-markdown-extensions.md。官方文档还提示,pymdownx.tabbedpymdownx.superfences 的其余配置项未经官方支持,可能产生意外结果,需自行承担风险。

本站点实际使用的完整配置

仓库根目录的 mkdocs.yml 中第 163~173 行即为本项目自身的内容标签页配置,可作为生产环境参考模板:

markdown_extensions:
  - pymdownx.superfences:
      custom_fences:
        - name: mermaid
          class: mermaid
          format: !!python/name:pymdownx.superfences.fence_code_format
  - pymdownx.tabbed:
      alternate_style: true
      combine_header_slug: true
      slugify: !!python/object/apply:pymdownx.slugs.slugify
        kwds:
          case: lower

这里除了 alternate_style 外还使用了两个进阶选项:

  • combine_header_slug: true:将所在标题(header)的 id 前置拼接到每个标签页的 id 上,避免不同小节里同名的标签页生成重复锚点;
  • slugify(通过 pymdownx.slugs.slugify 并指定 case: lower):将标签文本转为小写形式的 slug,生成更可读的锚点 id,详见后文"锚点链接"一节。

此外,mkdocs.yml 第 47 行保留了 # - content.tabs.link 的注释示例,即全站联动标签页功能默认关闭,按需开启即可(见下文"全站联动"一节)。

用法:标签页的 Markdown 语法

内容标签页使用 === 语法声明。最典型的场景是分组代码块——用不同标签展示同一程序的多语言实现:

=== "C"

    ``` c
    #include <stdio.h>

    int main(void) {
      printf("Hello world!\n");
      return 0;
    }
    ```

=== "C++"

    ``` c++
    #include <iostream>

    int main(void) {
      std::cout << "Hello world!" << std::endl;
      return 0;
    }
    ```

需要注意缩进规则:标签后的内容必须整体缩进 4 个空格(与列表项子内容一致),否则不会被解析为标签页内容。当标签页内恰好只有一个代码块时,它是"代码块标签页"的特殊形态,渲染时标签与代码块之间不产生水平间距;一旦标签页内包含超过一个代码块,则自动出现水平间距以区分多个内容块。

分组任意内容

标签页并不局限于代码,普通 Markdown 内容同样可以分组。例如用无序列表与有序列表展示同一主题的两种表达方式:

=== "Unordered list"

    * Sed sagittis eleifend rutrum
    * Donec vitae suscipit est
    * Nulla tempor lobortis orci

=== "Ordered list"

    1. Sed sagittis eleifend rutrum
    2. Donec vitae suscipit est
    3. Nulla tempor lobortis orci

需要说明的是,标签页之间永远不会添加垂直间距;如果希望在不同标签间留出垂直空间,可以把标签页再嵌套进其他块元素(如告警块、引用块)中实现。

嵌入其他块元素(嵌套)

在启用 pymdownx.superfences 后,标签页内可包含任意嵌套内容——包括再次嵌套的标签页,以及被嵌入到告警块(admonitions)、引用块等其他块级元素之中。下面的示例把一个标签页整体放进 !!! example 告警块里:

!!! example

    === "Unordered List"

        ``` markdown
        * Sed sagittis eleifend rutrum
        * Donec vitae suscipit est
        * Nulla tempor lobortis orci
        ```

    === "Ordered List"

        ``` markdown
        1. Sed sagittis eleifend rutrum
        2. Donec vitae suscipit est
        3. Nulla tempor lobortis orci
        ```

这种"块中块"能力正是 SuperFences 带来的:它允许代码块与内容块在彼此内部任意嵌套,包括告警块、列表与标签页。官方文档中关于 SuperFences 的说明见 docs/setup/extensions/python-markdown-extensions.md

锚点链接:给每个标签页一个可分享地址

从版本 9.5.0 起(该特性标注为"实验性"),Material for MkDocs 会为每个内容标签页自动生成锚点链接。渲染后,标签页的标签会被包裹为一个链接,你可以通过右键复制链接或在浏览器新标签页中打开,从而精确定位到某一标签页:

  • 在同一页面或其他页面引用该锚点即可实现跳转;
  • 例如指向本文档示例中第三个标签页的链接可写作 #anchor-links--or-even-me

该行为对应源码 src/templates/assets/javascripts/components/content/tabs/index.ts 中的实现:组件挂载时把每个标签 label 的内容替换为 <a href="#<label.htmlFor>">,并拦截普通点击(保留 Ctrl/⌘ + 点击、新标签页打开等浏览器行为),通过 history.replaceState 更新 URL 哈希后触发标签切换,从而做到"复制链接而不发生页面滚动"。

让锚点更可读:slugify

默认生成的标签 id 形如 __tabbed_N(数字序号)。Python Markdown Extensions 9.6 起为内容标签页引入了 slug 化支持,可将标签文本转换为更美观、可读的锚点。在原文档的提示中给出了如下配置:

markdown_extensions:
  - pymdownx.tabbed:
      slugify: !!python/object/apply:pymdownx.slugs.slugify
        kwds:
          case: lower

上述写法将标签文本转成小写 slug(例如标签 "Open me in a new tab ..." 会得到类似 open-me-in-a-new-tab- 的锚点);若希望保留大小写,可去掉 kwds 部分,写成 slugify: !!python/object/apply:pymdownx.slugs.slugify {}。详细的选项说明见 docs/setup/extensions/python-markdown-extensions.md。仓库自身即采用了 case: lower 配置(见 mkdocs.yml)。

全站联动:content.tabs.link

从版本 8.3.0 起,Material for MkDocs 提供"联动内容标签页"特性:基于标签文本(label)而非位置,将全站所有同名标签页联动起来——用户点击某一处标签后,整站其他位置同名的标签页会同步激活。启用方式:

theme:
  features:
    - content.tabs.link

启用后效果如下图所示(上方为启用状态,下方为禁用状态):

启用 content.tabs.link 后,全站同名标签页联动切换

未启用联动时,每个标签页组彼此独立

该功能有几个值得注意的行为细节:

  • 按标签名匹配而非按位置匹配:无论同一容器内标签的顺序如何,只要标签文本相同就会被联动激活;
  • 与即时加载(instant loading)完全集成:联动状态在页面跳转间保持,不会因 SPA 式加载而丢失。关于即时加载的说明见 docs/setup/setting-up-navigation.md
  • 跨页面持久化:用户点击的标签会被记住,后续访问站点时自动恢复。

底层实现:状态同步与持久化

联动逻辑在 src/templates/assets/javascripts/components/content/tabs/index.ts 中实现。核心流程如下:

  1. 组件通过 feature("content.tabs.link") 判断该特性是否启用;
  2. 当用户切换标签时,读取当前激活标签的 innerText 作为匹配键,遍历全站所有带 data-tabs 属性的标签页组,找到文本相同的标签并触发 input.click()
  3. 为防止联动触发连锁递归,被程序激活的标签会先打上 data-md-switching 标记,处理时跳过该次被动切换;
  4. 激活的标签名被写入浏览器 localStorage__tabs 键(__md_set("__tabs", ...)),实现跨页面记忆。

而页面首次加载时的状态恢复由 src/templates/partials/javascripts/content.html 完成:该脚本读取 __tabs,若其值为数组,则遍历每个 .tabbed-set 中同名标签并勾选对应的隐藏 input;随后另一个脚本(同文件第 42~46 行)根据 URL 中的 # 哈希定位目标标签(哈希以 __tabbed_ 开头的 input)并自动激活,与前述锚点链接配合实现"带标签定位的深链接"。

源码级原理:组件如何驱动标签页

从源码结构看,内容标签页是一套完整的"隐藏 radio input + label 标记"模式(每个标签对应一个 input,勾选即切换内容面板),前端负责把这一基础机制打磨成流畅的交互组件。以 src/templates/assets/javascripts/components/content/tabs/index.ts 为例,组件挂载(mountContentTabs)时依次完成以下工作:

  • 指示器动画:监听标签切换事件,计算激活标签的偏移与宽度,写入 --md-indicator-x--md-indicator-width 两个 CSS 变量,驱动底部滑块平滑移动(第 147~165 行);
  • 标签栏滚动:当激活标签超出可视区域时,将 .tabbed-labels 容器平滑滚动到目标位置(第 156~164 行);
  • 分页按钮:通过 src/templates/assets/javascripts/templates/tabbed/index.tsxrenderTabbedControl 渲染上一页/下一页按钮(.tabbed-control--prev/next),并在标签条到达边界时自动隐藏(第 174~202 行)——这正是移动端窄屏下标签过多时的横向翻页能力来源;
  • 深链接定位:订阅 URL 目标变化,若目标就是本组件内的某个 input 则模拟点击(第 204~210 行);
  • 媒体自动暂停:切换标签时自动暂停不可见的 <audio>/<video> 元素(第 280~292 行),避免多标签内容中的媒体互相干扰。

观察组件依赖可发现,标签切换状态由 watchContentTabs(第 98~111 行)统一封装为可观测流,初始激活项取"当前已勾选的 input,否则取第一个 input",这保证了页面刷新或恢复 __tabs 状态后标签栏与指示器始终一致。

小结

内容标签页是 mkdocs-material 文档中"多语言/多环境示例"的高频利器:启用 pymdownx.superfences + pymdownx.tabbedalternate_style: true)即可获得代码块与任意内容的嵌套分组能力;9.5.0 起自动生成的锚点链接让每个标签都可被深链接引用,配合 slugify 可获得可读的锚点 id;content.tabs.link 则让全站同名标签联动,并借助 localStorage 与即时加载实现跨页面记忆。若需要对照官方扩展的参数细节,可进一步查阅 docs/setup/extensions/python-markdown-extensions.md;源码实现则以 src/templates/assets/javascripts/components/content/tabs/index.tssrc/templates/partials/javascripts/content.html 为入口继续深入。

热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
34
18
docsdocs
暂无描述
Markdown
900
5.83 K
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.15 K
2.77 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.36 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
929
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.94 K
1.03 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
534
603
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.47 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
398
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.05 K
529