语义化标签是辅助技术识别页面结构的唯一依据,原生标签(如nav、main、label)具备隐式行为与严格嵌套要求,手动添加role或错误结构会导致键盘导航失效、焦点丢失、AT跳过内容等问题。

语义化标签不是“让页面更好看”的可选项,而是屏幕阅读器能正确识别导航、主体、表单等关键区域的唯一依据。 没有它,辅助技术只能看到一堆无意义的 div 和 span,就像让人在没门牌号的楼里找房间——根本无从下手。
为什么 nav 不能被 div role="navigation" 替代
原生 nav 元素自带隐式行为:浏览器自动为其添加 role="navigation",并确保它响应屏幕阅读器快捷键(如 NVDA 的 Insert+Tab),支持键盘焦点进入/退出,且能正确同步 aria-expanded 等状态。而手动加 role 的 div:
- 不自动获得
tabindex,需手动补,否则键盘用户无法聚焦 - 不响应空格/回车激活,除非额外监听事件
- 老旧组合(如 IE11 + JAWS)可能完全忽略该
role - 若内部只放纯文本、没可聚焦子元素,屏幕阅读器会跳过整个区域
main 缺失或嵌套错误时,视障用户怎么定位正文
main 是页面中唯一代表核心内容的容器,它的存在、唯一性与 DOM 位置直接决定“跳转到主要内容”功能是否生效:
- 重复出现:可访问性树断裂,部分 AT(如旧版 VoiceOver)只识别第一个,其余被忽略
- 被包裹在
div、table或section内:浏览器可能丢弃节点,或导致语义层级错乱 - 与
header/footer并列但中间夹着无语义div:破坏body→main的直系路径,AT 无法准确定位起始点 - SSR 场景下,服务端占位
div#root若包裹了main,等于主动阉割其语义
label 和 fieldset 绑定失效的底层原因
即使写了 label for="email" 和 input id="email",仍可能被跳过——问题常不在语法,而在执行环境:
立即学习“前端免费学习笔记(深入)”;
- ID 含非法字符(如
user-email@domain):HTML 规范禁止@在 ID 中,for匹配失败 - 动态框架(React/Vue)未显式设置
id,或用随机值生成却未同步更新for -
label内容为空或仅含空格:某些 AT(尤其是移动端 VoiceOver)直接跳过该标签 -
fieldset被div包裹后再设role="group":辅助技术依赖原生嵌套关系,div中间隔开会切断语义链,旧版 JAWS 可能完全忽略分组标题 -
legend不是fieldset的第一个子元素:部分 AT 无法将其识别为该分组的标题
最易被忽略的一点:语义化不是“写对标签就完事”,而是要确保它们在真实渲染后的 DOM 结构中保持合法、直系、无污染。任何一层无关 div、无效 ID、或动态生成时的属性不同步,都会让整条语义链在关键时刻断掉。



















