html无障碍可访问性必须从开始,正确使用语义标签、严守结构主干:lang值须符合ietf标准,须为直接子元素且唯一,标题层级不可断裂,和不可用模拟。

直接说结论:HTML 无障碍可访问性不是靠堆 aria- 属性补救出来的,而是从 开始、用对语义标签、守住结构主干的系统性选择。漏掉任何一环,后续所有 ARIA 注入、JS 补丁、CSS 优化都只是在掩盖结构性缺陷。
lang 属性写错或缺失,屏幕阅读器就“听不懂中文”
很多老项目模板里写 lang="ch" 或 lang="zh",甚至完全没声明。这些值不符合 IETF 标准,NVDA、VoiceOver 会 fallback 到英文语音引擎,把“提交表单”读成 “ti jiao biao dan”,分词错、声调崩、用户无法理解。
- 必须用
lang="zh-CN"(简体)、lang="zh-TW"(繁体)或lang="zh-HK",后缀不可省略 -
标签上声明,<meta>或局部lang无法兜底 - 多语言页面需嵌套:
<p lang="en">Hello</p>,不能靠 JS 拼接lang值——首屏 HTML 必须已带对
不是普通区块,它是键盘用户的“正文入口”
老旧系统常把整个页面包在 <div class="wrapper"> 里再塞 <code><main></main>,或服务端模板 include 多次导致多个 <main></main>。结果是 NVDA 按 M 键进不去正文,用户卡死在导航区。
-
<main></main>必须是的**直接子元素**,且全局只能出现一次 - 禁止嵌套:
<main><div><main> 是 axe 工具标为 critical 的严重错误 <li>组件化框架中,<code><main></main>应由布局层统一控制,子组件不得擅自输出 -
<nav></nav>可并列多个,但<main></main>是唯一主干,不能当样式容器用 - 常见原因:
display: none隐藏了某个<h3></h3>但 DOM 还在;JS 动态插入标题未校验层级;第三方卡片组件默认用<h2></h2>,嵌套在<h2></h2>主区下 - 修复方式:删 DOM,而非仅视觉隐藏;若必须保留,改用
aria-hidden="true"+ 视觉隐藏类 - 每个
<section></section>应以<h2></h2>或更高级别标题开头(HTML5 允许重置层级,但前提是显式提供) - 禁用
<div class="title"> 模拟标题——语义缺失无法被任何 ARIA 补救 <h3>button 和 a 标签不是“看起来像就行”,它们自带交互契约</h3> <p>用 <code><div> 模拟按钮,哪怕加了 <code>role="button",也缺了浏览器原生保障:可聚焦、Tab 可进入、回车/空格可触发、自带状态管理。漏掉任意一项,键盘用户就会卡住。- 必须手动补:
tabindex="0"(否则键盘根本进不去) - 必须监听
onkeydown处理Enter和Space(否则按空格不响应) - 带状态的要同步
aria-pressed或aria-expanded - 禁用时必须同步
disabled属性和视觉样式(仅 CSS 灰掉不行) -
<a href="#"></a>跳转无意义锚点,会破坏历史栈且无语义——该用<button type="button"></button>就别硬套链接
真正难的不是加
aria-label,而是把旧代码里满屏的<div> 替换成 <code><header></header>、<nav></nav>、<main></main>、<section></section>,并确保它们的嵌套顺序符合原生语义逻辑。一旦结构跑偏,后续所有 ARIA 注入都是无效劳动。 - 必须手动补:
标题层级断裂 = 信息架构塌方,不是“体验差”
用户按 H 键(H1→H2→H3…)跳转时,<h2></h2> 后直接 <h4></h4>,中间缺了 <h3></h3>,AT 就会判定章节结束。这不是提示弱,是逻辑断层——内容还在继续,但辅助技术认为“到此为止”。











