大纲算法
HTML 文档大纲(Document Outline)是指根据页面中的标题元素(h1-h6)和分区元素(section、article、aside、nav)自动生成的内容层次结构。大纲算法最初由 HTML5 规范定义,但在实际中经历了重大演变。
前置知识
阅读本节前,建议先了解:屏幕阅读器支持
基础概念
什么是文档大纲
文档大纲是 HTML 文档的逻辑结构,类似于书籍的目录。它由标题元素和分区元素共同构建,反映内容的层次关系:
文档大纲示例:
1. 网站名称(h1)
1.1 主导航(nav)
2.1 文章标题(article > h2)
2.1.1 第一节(section > h3)
2.1.2 第二节(section > h3)
2.2 相关文章(aside > h2)
3.1 页脚(footer)大纲算法的历史演变
| 阶段 | 时间 | 说明 |
|---|---|---|
| HTML4 大纲 | 1997-2010 | 仅基于 h1-h6 的数字层级 |
| HTML5 大纲算法 | 2010-2014 | 基于 section/article + h- 级别 |
| 大纲算法废弃 | 2014-2018 | 浏览器未实现,规范被标记为"at risk" |
| 当前实践 | 2018-至今 | 回归基于 h1-h6 的传统做法 |
语法与使用
传统大纲(HTML4 方式)
html
<!-- HTML4 风格:标题层级严格递减 -->
<h1>网站名称</h1>
<h2>文章标题</h2>
<h3>第一节</h3>
<h4>子节</h4>
<h3>第二节</h3>
<h2>侧边栏标题</h2>
<h2>页脚标题</h2>HTML5 大纲算法(理论)
html
<!-- HTML5 理论:每个分区重新开始标题层级 -->
<body>
<h1>网站名称</h1> <!-- Level 1 -->
<section>
<h1>文章标题</h1> <!-- 每个分区都可以有自己的 h1 -->
<section>
<h1>第一节</h1> <!-- 也是 h1,但大纲中是子级 -->
</section>
</section>
<section>
<h1>另一篇文章</h1> <!-- 也是 Level 1 的 h1 -->
</section>
</body>重要提示:HTML5 大纲算法从未被任何主流浏览器实现。屏幕阅读器也不依赖它。
详细说明
为什么大纲算法未被实现
- 浏览器厂商不支持:Chrome、Firefox、Safari 都没有实现
- 屏幕阅读器不使用:NVDA、JAWS 使用自己的导航逻辑
- SEO 工具不使用:Google、Bing 不依赖大纲算法
- 与实际需求不符:开发者更习惯传统标题层级
- 破坏现有页面:大量页面基于 HTML4 标题层级编写
当前最佳实践:传统标题层级
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>大纲算法最佳实践</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, sans-serif; }
.site-header { background: #2c3e50; color: #fff; padding: 1rem 2rem; }
main { max-width: 800px; margin: 2rem auto; padding: 0 2rem; }
.outline-demo { margin: 2rem 0; }
.outline-demo h2 { margin: 1.5rem 0 0.75rem; }
.outline-demo h3 { margin: 1rem 0 0.5rem; color: #475569; }
.outline-demo h4 { margin: 0.75rem 0 0.5rem; color: #64748b; }
.outline-demo p { line-height: 1.7; color: #334155; margin-bottom: 0.75rem; }
.site-footer { background: #2c3e50; color: #94a3b8; text-align: center; padding: 1rem; margin-top: 2rem; }
/* 大纲可视化 */
.outline-visual {
background: #f8fafc; border: 1px solid #e2e8f0;
border-radius: 8px; padding: 1.5rem; margin-top: 2rem;
font-family: monospace; font-size: 0.9rem;
line-height: 2;
}
</style>
</head>
<body>
<header class="site-header">
<h1>技术博客</h1>
</header>
<main>
<div class="outline-demo">
<!-- h1: 页面唯一主标题 -->
<h1>CSS 布局完全指南</h1>
<p>本文将介绍 CSS 中的三种主要布局方式...</p>
<!-- h2: 主要章节 -->
<h2>Flexbox 布局</h2>
<p>Flexbox 是一种一维布局模型...</p>
<!-- h3: 子章节 -->
<h3>Flex 容器属性</h3>
<p>Flex 容器有以下主要属性...</p>
<!-- h4: 更细的子节 -->
<h4>flex-direction</h4>
<p>定义主轴方向...</p>
<h4>justify-content</h4>
<p>控制主轴上的对齐方式...</p>
<h3>Flex 项目属性</h3>
<p>Flex 项目的属性...</p>
<!-- 回到 h2 -->
<h2>Grid 布局</h2>
<p>Grid 是二维布局系统...</p>
<h3>Grid 容器属性</h3>
<p>Grid 容器有以下主要属性...</p>
<h2>定位布局</h2>
<p>CSS 定位是传统的布局方式...</p>
</div>
<!-- 大纲可视化 -->
<div class="outline-visual">
<strong>文档大纲:</strong><br>
1. CSS 布局完全指南(h1)<br>
2.1 Flexbox 布局(h2)<br>
2.1.1 Flex 容器属性(h3)<br>
2.1.1.1 flex-direction(h4)<br>
2.1.1.2 justify-content(h4)<br>
2.1.2 Flex 项目属性(h3)<br>
2.2 Grid 布局(h2)<br>
2.2.1 Grid 容器属性(h3)<br>
2.3 定位布局(h2)
</div>
</main>
<footer class="site-footer">
<p>© 2024 技术博客. All rights reserved.</p>
</footer>
</body>
</html>多页面标题层级
html
<!-- 首页 -->
<body>
<h1>网站名称</h1> <!-- 唯一 h1 -->
<main>
<h2>最新文章</h2>
<article>
<h3>文章标题</h3> <!-- article 内从 h3 开始 -->
</article>
</main>
</body>
<!-- 文章页 -->
<body>
<h1>文章标题</h1> <!-- 唯一 h1:文章标题 -->
<main>
<h2>第一节</h2>
<h3>子节</h3>
<h2>第二节</h2>
</main>
</body>实际建议
| 建议 | 说明 |
|---|---|
| 每页一个 h1 | h1 包含页面最重要的关键词 |
| 层级不跳级 | h1 -> h2 -> h3,不要 h1 -> h3 |
| section 内标题 | section 内标题作为其子级 |
| article 内标题 | article 内标题作为其子级 |
| 忽略 HTML5 大纲 | 使用传统 h1-h6 层级 |
| 工具验证 | 使用浏览器扩展检查标题层级 |
实战示例
标题层级检查工具
javascript
// 简单的标题层级检查器
function checkHeadingHierarchy() {
const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
let prevLevel = 0;
const issues = [];
headings.forEach((heading, index) => {
const level = parseInt(heading.tagName.charAt(1));
const text = heading.textContent.trim().substring(0, 50);
// 检查跳级
if (prevLevel > 0 && level > prevLevel + 1) {
issues.push({
type: 'skip',
from: prevLevel,
to: level,
text: text,
element: heading
});
}
// 检查多个 h1
if (level === 1 && prevLevel === 1) {
issues.push({
type: 'multiple-h1',
text: text,
element: heading
});
}
prevLevel = level;
});
return issues;
}
// 使用
const issues = checkHeadingHierarchy();
issues.forEach(issue => {
console.log(`问题: ${JSON.stringify(issue)}`);
});注意事项
关于 HTML5 大纲算法的澄清
- 不要依赖它:浏览器没有实现,不会影响实际渲染
- 不要据此编写代码:不要因为大纲算法就滥用 h1
- 关注实际效果:以屏幕阅读器和搜索引擎的实际表现为准
最佳实践
- 使用传统标题层级:h1 -> h2 -> h3,严格递减
- 每页一个 h1:h1 是页面的主标题
- section/article 影响上下文:分区内的标题属于该分区
- 使用工具验证:Chrome Lighthouse 或 heading 顺序检查工具
- 保持一致性:整个网站使用相同的标题层级策略
下一节
继续学习:id 与 class