必须用h1–h6严格逐级嵌套构建文档层级,h1唯一作主标题,h2–h4依次对应章/条/款/项,禁跳级;目录须用<nav aria-label="文档目录">包裹<ol>,链接href精准指向标题id,支持原生锚点跳转与CSS平滑滚动。

用 h1–h6 + nav 实现语义化目录结构
HTML 本身不提供“自动生成目录”功能,但浏览器能根据标题层级自动构建导航逻辑。关键不是写 JS 动态生成,而是先搭对骨架:用 h1 到 h6 严格对应内容层级,再用 nav 包裹目录入口。
常见错误是用 div 或 span 模拟标题,比如 <div class="h2">第二条</div> —— 这会让屏幕阅读器读不出层级,PDF 导出也丢编号。
-
h1只能出现一次,作为整篇文档主标题(如“中华人民共和国合同法”) -
h2对应章/条级(如“第一条”“第一章”),必须带id(如id="article-1") -
h3用于款、节,h4用于项,禁止跳级(h2后直接h4是无效结构) - 目录容器必须是
<nav aria-label="文档目录">,不能只用div
锚点链接必须用原生 a href="#id",别碰 scrollIntoView
目录项本质是跳转入口,所有链接都该指向页面内已有 id 的标题。JavaScript 滚动控制(如 element.scrollIntoView())只是锦上添花,不是必需;禁用 JS 时,原生锚点仍要可用。
容易踩的坑:
立即学习“前端免费学习笔记(深入)”;
- 链接写成
<a href="javascript:void(0)" onclick="jump('article-2')">第二条</a>—— 屏幕阅读器无法朗读目标,键盘 Tab 也无法聚焦到真实位置 - 动态生成的
id包含空格或中文(如id="第一条"),某些旧环境解析失败,应转为英文+数字(id="article-1") - 多个标题用了同一个
id,导致点击后跳错位置
纯 CSS 实现“……”引导线,不用 JS 计算宽度
Word 风格的目录引导线(如“第一条…………12”)靠 CSS 就能实现,核心是利用 border-bottom 和定位遮盖。
关键代码片段:
<p class="toc-item"> <span class="toc-title">第一条</span> <span class="toc-page">12</span> </p>
CSS 部分:
.toc-item {
position: relative;
padding-right: 5em; /* 给页码留空间 */
}
.toc-title {
position: relative;
z-index: 2;
background-color: white; /* 遮盖下划线 */
}
.toc-page {
position: absolute;
right: 0;
top: 0;
}
.toc-item::after {
content: "";
position: absolute;
bottom: 0.5em;
left: 0;
right: 0;
border-bottom: 1px dotted #000;
z-index: 1;
}注意:background-color: white 必须加,否则点线会从标题文字底下穿过去;z-index 值不重要,只要 .toc-title 高于 ::after 即可。
打印和 PDF 导出时,counter-reset 比 JS 更可靠
后台导出 PDF 时,常要求显示页码(如“第一条 ………… 第3页”)。用 JS 注入页码在无头浏览器中不稳定,而 CSS 的 counter-reset + counter-increment 在多数 PDF 工具(如 wkhtmltopdf、WeasyPrint)中支持良好。
示例(配合 h2 标题):
body { counter-reset: toc-counter; }
h2::before {
counter-increment: toc-counter;
content: "第 " counter(toc-counter) " 条 ";
}
@media print {
.toc-page::after {
content: "第 " counter(page) " 页";
}
}但要注意:页码仅在 @media print 下生效,且依赖 PDF 工具对 CSS Paged Media 的支持程度;如果工具不支持,就老老实实手动写页码字段,别硬套 CSS。
最易被忽略的是:目录结构必须先验证 HTML 有效性(用 W3C Validator),哪怕只差一个闭合标签,PDF 导出时层级就全乱了。



















