锚点跳转
锚点机制:GitHub 标题 slug 规则、自定义锚点、页内与跨文档跳转的写法与排错。
认知导入(Layer 1 进阶层) 前置知识:017 链接与图片(锚点链接就是目的地为
#片段的链接)。 边界说明:Markdown 标题会自动生成锚点(HTML id),锚点规则由各渲染器自行定义——本篇以 GitHub 规则为主线,其余平台给出差异提示。锚点跳转失效的原因九成是”slug 算错了”。 强制练习:写一个中文标题和一个英文标题,各生成一次锚点并链接过去,在 GitHub 预览验证能否跳转。
1. 锚点是什么
锚点是页面内的定位标记,对应 HTML 元素的 id 属性。URL 中 # 后面的部分叫片段标识符(fragment),浏览器加载页面后滚动到对应 id 的元素:
URL: https://example.com/docs#installation
↑
片段标识符,对应 id="installation" 的元素
Markdown 写不了 <a name> 也能玩锚点——渲染器会为每个标题自动生成 id,于是”链接到某标题”只需要知道标题的 slug(URL 化的字符串)。
2. GitHub 的标题 slug 规则
GitHub 的生成算法(对仓库文件、Issue、评论一致)分四步:
- 转小写(英文部分);
- 删除所有”非文字、非空格、非连字符”的字符(标点、符号被剔除);
- 空格替换为连字符
-(每个空格一个连字符,不合并); - 重复的 slug 追加
-1、-2后缀。
| 标题源码 | 生成的锚点 | 说明 |
|---|---|---|
## Getting Started | #getting-started | 小写 + 空格变连字符 |
## What's New? | #whats-new | 撇号与问号被删除 |
## API v2.0 | #api-v20 | 点号被删除 |
## C++ 编程 | #c-编程 | + 被删除,中文保留 |
## A --- B | #a-----b | 原有连字符保留、空格各变一个 - |
## 安装指南 | #安装指南 | 中文原样保留 |
第二个 ## 示例 | #示例-1 | 重复 slug 加序号 |
两个高频误区:
- 连字符不会被合并:
A --- B这类标题生成a-----b(原连字符照留、空格逐个转换),凭感觉写#a-b必然跳转失败; - emoji 也参与 slug:GitHub 会把 emoji 转成短代码文本(如
## 🚀 发布生成#-发布),这种标题不要依赖锚点链接。
GitLab 的规则与 GitHub 基本兼容;Obsidian、Hugo、VuePress 等各有细节差异(是否剔除中文、是否转拼音等)。跨平台文档的标题尽量用”字母数字 + 单个空格”,slug 才有一致性可言。
3. 页内跳转
3.1 链接到标题
## 目录
- [安装](#安装)
- [快速开始](#getting-started)
## 安装
## Getting Started
链接目的地就是 # + slug,与普通链接语法完全一致(见 markdown/050-LinkImage)。
3.2 中文标题直接写中文锚点
GitHub 保留中文字符,链接里直接写中文即可,浏览器会做 URL 编码:
[跳到安装步骤](#安装步骤)
## 安装步骤
内部工具链(某些静态站点生成器、IDE 插件)对中文 slug 处理不一致,纯内部文档没问题,公开发布前在目标平台逐个点一遍。
4. 自定义锚点
自动 slug 会随标题文字变化,且”重复标题加 -1”不可控。需要稳定锚点时显式声明。
4.1 HTML 锚点标签(最通用)
<a name="changelog-v2"></a>
## 更新日志
[跳到更新日志](#changelog-v2)
空锚点标签放在目标位置的前一行,不影响渲染。GitHub 官方文档推荐 <a name="...">;多数其他渲染器(站点生成器、IDE 预览)同样支持 id 属性。需要跨渲染器稳定的场景可以两个都写:<a id="x" name="x"></a>。
4.2 扩展属性语法(仅部分渲染器)
## 更新日志 {#changelog-v2}
{#id} 是 Pandoc、kramdown、PHP Markdown Extra 等的扩展;GitHub 不支持(整段被当标题文字或忽略),只在自己掌控渲染管线的项目里使用。
5. 跨文档与跨页锚点
<!-- 链接到同仓库其他文件的某章节(GitHub 支持) -->
[参见安装文档](./install.md#安装步骤)
<!-- 链接到渲染后的 HTML 页面锚点 -->
[查看页面](https://example.com/docs/page.html#section)
<!-- 站点根路径写法(仅站点环境有效,GitHub 仓库内无效) -->
[文档首页](/docs/index.md#top)
跨文档锚点的生效条件比页内链接苛刻:目标文件必须被同一渲染管线处理,且 slug 规则一致。GitHub 上仓库内 .md 互链是支持的;一旦文档导出为 PDF 或迁移站点,跨文件锚点往往需要重建。
6. 实战场景
6.1 返回顶部
<a name="top"></a>
# 长文档标题
(大量内容……)
[返回顶部](#top)
6.2 顶部横向导航
[安装](#安装) | [配置](#配置) | [FAQ](#faq)
6.3 长文档交叉引用
在正文中引用其他章节时用锚点链接而非”见上文第 3 节”这类模糊表述,章节增删后链接要么仍指向正确位置、要么在死链检查中显式报错:
环境变量配置见[高级配置](#高级配置)。
7. 排错与验证
锚点跳转失效按固定顺序排查:
| 现象 | 原因 | 解决 |
|---|---|---|
| 点击无反应 | slug 不匹配(大小写、连字符数) | 按 GitHub 规则重算 slug |
| 标题改了链接失效 | slug 随标题文字变化 | 关键位置用 <a name> 固定 |
| 重复标题跳错位置 | 自动加了 -1 后缀 | 用自定义锚点区分 |
| 中文锚点在别处失效 | 目标渲染器 slug 规则不同 | 统一用英文标题或显式 id |
| 跨文件锚点失效 | 平台不支持或路径错误 | 确认平台支持 .md#锚点 互链 |
验证工具:
# markdown-link-check 可以检查页内锚点(配置 page 下 anchor 校验)
npx markdown-link-check README.md
浏览器端调试:在渲染页面控制台列出全部 id,与目录链接逐一比对:
document.querySelectorAll('[id]').forEach((el) =>
console.log(`#${el.id} → ${el.textContent.trim().slice(0, 30)}`)
);
8. 最佳实践
- 标题命名优先”字母数字 + 单个空格”:slug 在各平台表现一致,跨平台最稳。
- 被外部引用的位置用显式锚点:
<a name>不随标题改动失效,适合 FAQ、API 条目等深链目标。 - 避免在标题里放代码、emoji 与标点:锚点难看且易错。
- 重复标题必然产生
-1后缀:要么改标题,要么自定义锚点。 - 发布前逐个点击:锚点错误不会在任何检查里自动暴露(除非配置了死链检查),人工点击是最便宜的验证。
小结
- 初学者要点:标题自动生成锚点;页内跳转写
[文字](#标题);GitHub 规则是”小写、删标点、空格变连字符”;中文标题直接写中文锚点。 - 进阶注意:连字符不合并、重复标题加
-1,凭感觉拼 slug 是跳转失败的第一原因;需要稳定深链用<a name>显式锚点;{#id}语法 GitHub 不支持;跨文档锚点依赖同渲染管线,导出或迁移时重建。