html可访问性核心在于正确使用原生语义标签:必须唯一且为直接子元素,不得嵌套;须带标题并表逻辑分组;需真实语义而非类名模拟;表单控件必须绑定;标题层级须严格递进。

HTML可访问性不是加一堆aria-属性就能解决的,核心是让原生标签真正承担语义职责——结构对了,读屏器才不会“读丢”内容,键盘焦点才不会跳飞。
用对<main></main>、<section></section>和避免嵌套失焦
很多项目把整个页面塞进一个<div id="app">,<code><main></main>要么缺失,要么被包在<header></header>或<footer></footer>里。结果就是屏幕阅读器按Ctrl+Alt+Home(NVDA)根本跳不到主内容区。
-
<main></main>必须且只能出现一次,不能嵌套在<article></article>、<aside></aside>、<footer></footer>等标签内 -
<section></section>不是“视觉分隔线”,它代表有主题关联的一组内容,必须带<h2></h2>–<h6></h6>,不能只包<p></p> - 纯装饰性区块(比如广告位)别硬套
<section></section>,它默认带regionrole,会污染屏幕阅读器大纲树
别让<nav></nav>变成“导航类名容器”
写成<div class="nav"><ul></ul></div>,哪怕加了role="navigation",浏览器也不会把它识别为地标(landmark),键盘用户按D键跳转直接失效。
- 真实
<nav></nav>要包裹完整导航逻辑链:主导航、面包屑、页内锚点列表都算 - 多个
<nav></nav>必须加aria-label区分,例如:<nav aria-label="主导航"></nav>、<nav aria-label="页脚导航"></nav> - 响应式折叠菜单仍需保留在
<nav></nav>内,仅用hidden或aria-hidden="true"控制可见性,不可移除DOM
表单控件必须绑定<label></label>且禁用for/id错配
动态生成表单项时JS拼HTML容易漏掉<label></label>,或for值与实际id不一致。后果是屏幕阅读器完全读不出控件用途,“点击邮箱输入框”这类语音指令直接失效。
- 优先用显式包裹:
<label>邮箱<input type="email"></label>,比手动配for/id更可靠 - 禁用空
<label for="xxx"></label>——这会让阅读器静默跳过,用户根本不知道这是什么控件 - 多选/单选组必须用
<fieldset></fieldset>+<legend></legend>,否则组标题不会被读出
标题层级断裂比不用语义标签更致命
很多页面从<h2></h2>开始,或在<main></main>外堆了三个<h1></h1>。这对键盘用户和读屏用户是灾难:大纲树错乱,无法跳转到“产品介绍”板块。
- 全页只允许一个
<h1></h1>,代表页面核心主题(通常是logo或主标题) -
<main></main>内部标题必须严格递进:<h2></h2>→<h3></h3>→<h4></h4>,禁止跳级或降级 - CSS隐藏
<h1></h1>时,必须同步加aria-hidden="true",否则读屏会播报两次
最容易被忽略的是:可访问性退化往往不是因为没加ARIA,而是因为原生语义标签被当成“样式容器”用了——比如用<div class="button">代替<code><button></button>,或者把<time></time>写成纯文本。这些地方一旦松动,整页的无障碍结构就塌了一角。











