必须用开头且唯一并为直接子元素,标题层级不可断裂;缺失lang、嵌套或跳级标题将导致屏幕阅读器导航失效、乱码或跳过正文。

必须用 不写 正确写法只有两种主流值: 屏幕阅读器用户靠 H 键(如 H1/H2/H3)逐级跳转内容。一旦出现 常见断裂场景:CSS 隐藏了某个 没有 最常被跳过的其实是 开头,否则屏幕阅读器大概率读成英文或乱码;<main></main> 只能出现一次且直接子元素不能是 <div>;标题层级断裂(比如 <code><h2></h2> 后直接 <h4></h4>)会让导航完全失效。
lang 属性写错或缺失的后果
lang,或写成 lang="ch"、lang="cn"、lang="zh",浏览器和屏幕阅读器(如 NVDA、VoiceOver)就无法准确识别语言。中文内容可能被当作日文、韩文甚至英文朗读,语调错乱、分词错误,用户根本听不懂。lang="zh-CN"(简体中文)、lang="zh-TW"(繁体中文)。港澳地区可用 lang="zh-HK"。不要省略后缀,zh 单独存在不是 IETF 标准值,AT(辅助技术)兼容性差。
标签上必须声明,不能只在 <meta> 或某段文字里补lang 属性嵌套,比如一段英文引文:<p lang="en">...</p>
lang 值——得确保 SSR 或初始 HTML 就带对<main></main> 是页面唯一主内容区,它必须直接位于 下,不能包在 <div>、<code><section></section> 或其他容器里。如果嵌套了,NVDA 等工具会跳过它,或者误判为普通区块。
<nav></nav> 不是“所有链接集合”,而是**有明确导航意图的链接组**:主导航、面包屑、页内锚点跳转列表可以,但文章末尾的“相关阅读”或登录/注册链接就不该放进去——AT 用户按 N 键快速跳转时,会被带进一堆无关链接,体验崩坏。
aria-label 区分,比如:<nav aria-label="主导航"></nav>、<nav aria-label="页内目录"></nav>
<ol></ol> 而非 <ul></ul>,并给当前页加 aria-current="page"
<main></main> 内部禁止再出现 <main></main>,校验工具(如 axe)会直接报严重错误标题层级断裂的真实影响
<h2></h2> 后跟 <h4></h4>,中间缺了 <h3></h3>,他们就会“掉层”——以为章节结束,实际内容还在继续。这不是提示问题,是逻辑结构塌方。<h3></h3> 却没同步移除 DOM;JS 动态插入标题但没检查层级;组件库默认用 <h2></h2> 作为卡片标题,嵌套在 <h2></h2> 主区域下,变成 H2→H2。
<section></section> 应以一个 <h2></h2> 或更高级别标题开头(HTML5 允许 <section></section> 内部重置层级,但前提是显式提供标题)display: none 隐藏标题——改用 aria-hidden="true" + 视觉隐藏类,或直接删 DOMDOCTYPE 和 charset 的硬性前置条件
,浏览器会进入怪异模式(Quirks Mode),导致 <code><main></main>、<nav></nav> 等语义标签被忽略,AT 完全无法识别结构。这不是警告,是功能级失效。<meta charset="UTF-8"> 必须出现在 最前面(最好第一行),晚于它或放在 <title></title> 后,部分 WebView(尤其 Android 内嵌)会解析失败,中文变乱码,AT 读出来就是一串“”。
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> —— 过时且兼容性差Content-Type 也必须含 charset=utf-8,否则前端 meta 可能被覆盖<meta charset> 位置不可被插件挪动<main></main> 的直系子元素约束和 lang 的完整 IETF 格式——这两处出错,整个结构语义就从根上断了,后续加再多 ARIA 也救不回来。











