lang必须为IETF标准格式(如zh-CN)、<main>须为<body>直接子元素且唯一、标题层级必须连续,三者是可访问HTML硬性准入门槛;lang错致屏幕阅读器误读中文,<main>嵌套或重复使AT跳过主内容,标题断裂导致用户“掉层”无法导航。

直接写对 lang、<main> 和标题层级,比加一堆 ARIA 更管用——这三处写错,屏幕阅读器当场“失语”或“迷路”,不是体验打折,是功能瘫痪。
lang 属性必须严格匹配 IETF 标准格式
写成 lang="zh" 或 lang="ch",NVDA 和 VoiceOver 就会按英语音节逐字朗读中文内容,语义彻底断裂。真实场景里,用户听到的是“shì jiè”被读成 “shee-jer”,完全无法理解。
-
lang必须静态写在首屏 HTML 的<html>标签上,JS 运行时 patch 无效 - 只允许白名单值:
zh-CN、zh-TW、zh-HK;模板引擎必须校验locale变量是否落入其中,否则 SSR 输出即不可用 - 局部语言切换(如引文含英文)用嵌套
<p lang="en">,但根lang不可省略或错配
<main> 必须是 <body> 的直接子元素且全局唯一
多个 <main> 或嵌套在 <div class="container"> 里,NVDA 按 M 键会完全跳过主内容区——键盘用户根本找不到正文在哪。
- 验证方式:DevTools → Elements 面板搜索
<main,确认仅出现一次,且父节点是<body> - 禁止组件库中让子组件输出
<main>;布局层必须统一收口 - React/Vue 动态渲染、服务端 include 多次,都可能意外产生重复,需加运行时去重逻辑或构建时 lint 检查
标题层级必须连续,不能跳级或断裂
遇到 <h2> 后紧跟 <h4>,屏幕阅读器用户按 H 键导航会“掉层”——以为章节结束,实际内容还在继续,信息架构直接塌方。
立即学习“前端免费学习笔记(深入)”;
- 每个
<section>必须以<h2>或更高级别开头;若需重置层级,必须显式提供标题,不能留空 - 第三方组件默认用
<h2>作卡片标题,嵌套在<h2>主区下,立刻造成 H2→H2 断层 - JS 动态插入标题前,必须校验当前最大层级,否则
document.createElement('h3')可能直接跳到h5
别用 div 模拟 button,语义化标签才是第一道防线
看到 <div role="button" tabindex="0"> 就该立即叫停——它缺键盘事件监听、缺禁用状态同步、缺 focus 样式、缺 aria-pressed,漏一项,键盘用户就卡死。
-
<button>自带聚焦、回车/空格触发、role="button"、type="button"默认防提交,无需额外补 - 所有交互元素必须能被 Tab 访问:检查是否误设
tabindex="-1",或 CSS 把outline隐藏却没提供替代焦点样式 -
display: none或visibility: hidden的元素仍存在于 DOM,必须删节点或加aria-hidden="true"
真正难的不是写 ARIA,而是守住这四条线:语言标识、主内容锚点、标题骨架、交互语义。它们藏在 HTML 最底层,一旦松动,上层所有无障碍优化都变成空中楼阁。



















