必须使用语义化标签而非“看起来像”的div:自带role="navigation"且为地标,需aria-label区分多个;须为body直接子元素且唯一,缺失将导致跳转至页眉h1;必设type避免意外提交,图标按钮需aria-label;禁用状态须用disabled属性;所有语义标签需通过devtools验证可访问性树是否正确生成。

必须用对标签,而不是“看起来像”——<nav></nav>、<main></main>、<button></button> 这些不是装饰,是屏幕阅读器唯一能依赖的语义锚点;写错一个,用户可能得手动按键十几次才能摸到正文。
为什么 <div class="nav"> 在读屏软件里等于静音
<p><code><div> 没有内置 role,浏览器生成的可访问性树里它就是 <code>generic,读屏器既不播报“导航”,也不响应快捷键(比如 NVDA 的 N 键跳导航)。而 <nav></nav> 自带 role="navigation",且被所有主流读屏器固化为地标(landmark)。
- 多个
<nav></nav> 必须加 aria-label,否则全读作“导航”——用户分不清哪个是主导航、哪个是页脚面包屑
-
<nav></nav> 不能嵌套在 <table> 或 <code><ul></ul> 里,HTML 校验会失败,部分浏览器直接丢弃节点
- 里面必须直接包裹可聚焦元素(如
<a></a>、<button></button>),纯文本不构成有效导航内容
<main></main> 缺失或嵌套错误时,用户怎么找正文
<main></main> 是屏幕阅读器定位“用户真正想看的内容”的唯一可信锚点。缺失时,系统退而求其次:先找 role="main",再找不到就从第一个 <h1></h1> 开始算正文——但页眉里常有 <h1></h1>,结果“跳到主要内容”跳到了 Logo 上。
-
<main></main> 必须是 的直接子元素,不能被 <div class="container"> 包着
<li>全页只能有一个,重复或嵌套在 <code><header></header>、<footer></footer>、<nav></nav> 内都会导致语义断裂
- 里面不应混入广告、侧边栏、弹窗等非核心内容;若只有一个
<section></section>,不如直接用 <main><h2></h2></main>
<button></button> 不写 type 属性会触发意外提交
省略 type 时,浏览器默认为 submit。放在表单里,点一下就会触发表单提交——不仅功能错乱,还会打断读屏器对当前上下文的判断(比如正在编辑,突然跳转)。
-
type="button" 是最安全的兜底选择,尤其在组件库中封装按钮时应默认设该值
- 图标按钮(如 ×、?️)必须配
aria-label,仅靠 title 无效,且 title 不被键盘用户感知
- 禁用按钮必须用
disabled 属性,不能只靠 style="opacity: 0.5",否则辅助技术仍认为可操作
检查语义是否真生效的实操方式
光写对标签不够,得验证浏览器和辅助技术是否识别它。打开 Chrome DevTools → Elements 面板,右键元素 → “Inspect Accessibility Properties”,看 role、name、level 是否符合预期。
-
<img> 缺 alt,或写成 alt="" 却没确认是否真为装饰图,会导致读屏器跳过关键信息
-
<time datetime="2026-06-15"></time> 的 datetime 值格式错误(如写成 "2026/06/15"),机器无法解析时间语义
- 用
<div role="button"> 替代 <code><button></button>,却漏了 tabindex="0" 和键盘事件监听,键盘用户完全无法操作
最容易被忽略的点是:语义失效往往不是“没写标签”,而是“写了但嵌套错了”——比如 <main></main> 被包在 <section></section> 里,或者 <fieldset></fieldset> 中间插了个 <div>,这些结构断裂在视觉上毫无痕迹,却会让可访问性树直接断掉。</div>
<nav></nav> 必须加 aria-label,否则全读作“导航”——用户分不清哪个是主导航、哪个是页脚面包屑<nav></nav> 不能嵌套在 <table> 或 <code><ul></ul> 里,HTML 校验会失败,部分浏览器直接丢弃节点
<a></a>、<button></button>),纯文本不构成有效导航内容
<main></main> 缺失或嵌套错误时,用户怎么找正文
<main></main> 是屏幕阅读器定位“用户真正想看的内容”的唯一可信锚点。缺失时,系统退而求其次:先找 role="main",再找不到就从第一个 <h1></h1> 开始算正文——但页眉里常有 <h1></h1>,结果“跳到主要内容”跳到了 Logo 上。
-
<main></main>必须是的直接子元素,不能被<div class="container"> 包着 <li>全页只能有一个,重复或嵌套在 <code><header></header>、<footer></footer>、<nav></nav>内都会导致语义断裂 - 里面不应混入广告、侧边栏、弹窗等非核心内容;若只有一个
<section></section>,不如直接用<main><h2></h2></main> -
type="button"是最安全的兜底选择,尤其在组件库中封装按钮时应默认设该值 - 图标按钮(如 ×、?️)必须配
aria-label,仅靠title无效,且title不被键盘用户感知 - 禁用按钮必须用
disabled属性,不能只靠style="opacity: 0.5",否则辅助技术仍认为可操作 -
<img>缺alt,或写成alt=""却没确认是否真为装饰图,会导致读屏器跳过关键信息 -
<time datetime="2026-06-15"></time>的datetime值格式错误(如写成"2026/06/15"),机器无法解析时间语义 - 用
<div role="button"> 替代 <code><button></button>,却漏了tabindex="0"和键盘事件监听,键盘用户完全无法操作最容易被忽略的点是:语义失效往往不是“没写标签”,而是“写了但嵌套错了”——比如
<main></main>被包在<section></section>里,或者<fieldset></fieldset>中间插了个<div>,这些结构断裂在视觉上毫无痕迹,却会让可访问性树直接断掉。</div>
<button></button> 不写 type 属性会触发意外提交
省略 type 时,浏览器默认为 submit。放在表单里,点一下就会触发表单提交——不仅功能错乱,还会打断读屏器对当前上下文的判断(比如正在编辑,突然跳转)。
检查语义是否真生效的实操方式
光写对标签不够,得验证浏览器和辅助技术是否识别它。打开 Chrome DevTools → Elements 面板,右键元素 → “Inspect Accessibility Properties”,看 role、name、level 是否符合预期。











