语义化标签是屏幕阅读器理解页面结构的唯一可靠依据;不用等标签,屏幕阅读器只能读“div、div、div”,无法跳转或识别区域意图;和无内置语义,屏幕阅读器默认不播报其存在;自带焦点、触发和禁用逻辑,而需手动补全多项交互支持;是页面主体内容的强制性地标,一个页面仅能有一个且不可嵌套,缺失将导致用户平均下拉7–12次才能定位正文。

语义化标签不是“增强支持”,而是屏幕阅读器理解页面结构的**唯一可靠依据**。不用 <nav></nav>、<main></main>、<header></header> 这类标签,屏幕阅读器就只能读出一堆“div、div、div”,无法跳转、无法识别区域意图、也无法建立内容层级。
为什么 <div> 在屏幕阅读器里等于“沉默”
<p><code><div> 和 <code><span></span> 是纯容器,没有内置语义。屏幕阅读器默认不播报其存在,也不提供导航快捷键(比如 NVDA 的 D 跳 div、H 跳标题——但那是弱线索,不可靠)。它只朗读其中的文本,且不说明上下文。
- 错误示例:
<div class="nav">@#@#@#@#@#@#@#@#@#@0</div> → 屏幕阅读器只读“首页”,用户不知道这是导航区,也无法用快捷键跳过整个导航栏
- 正确写法:
<nav aria-label="主导航">@#@#@#@#@#@#@#@#@#@0</nav> → 朗读为“主导航,链接 首页”,并支持 N 键直接跳入/跳出
- 注意:
<nav></nav> 自带 role="navigation",无需手动加;但多个 <nav></nav> 时必须用 aria-label 或 aria-labelledby 区分,否则所有导航都叫“导航”
<button></button> 和 role="button" 的实际行为差异
<div class="nav">@#@#@#@#@#@#@#@#@#@0</div> → 屏幕阅读器只读“首页”,用户不知道这是导航区,也无法用快捷键跳过整个导航栏<nav aria-label="主导航">@#@#@#@#@#@#@#@#@#@0</nav> → 朗读为“主导航,链接 首页”,并支持 N 键直接跳入/跳出<nav></nav> 自带 role="navigation",无需手动加;但多个 <nav></nav> 时必须用 aria-label 或 aria-labelledby 区分,否则所有导航都叫“导航”<button></button> 和 role="button" 的实际行为差异二者在屏幕阅读器中播报效果可能相似,但交互能力天差地别:
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
-
<button></button>:自动获得键盘焦点、空格/回车触发、disabled状态自动禁用交互与朗读、自带 focus outline 样式 <div role="button" tabindex="0">:需手动补全 <code>tabindex="0"、onkeydown监听空格/回车、aria-disabled管理禁用状态、CSS 处理焦点样式——漏一项,键盘用户就卡住- 真实坑点:React/Vue 项目里用
<div> 模拟按钮,测试时只用鼠标点,上线后视障用户完全无法提交表单 <h3> <code><main></main>不是可选装饰,而是强制性地标几乎所有主流屏幕阅读器(NVDA、VoiceOver、JAWS)都把
<main></main>当作“页面主体内容”的唯一可信标识。它的使用有硬约束:- 一个页面只能有一个
<main></main>,且不能嵌套在<article></article>、<aside></aside>、<header></header>等其他语义容器内 - 没写
<main></main>?屏幕阅读器会退而求其次找role="main",再找不到就从第一个<h1></h1>开始当主体——极易误判(比如把页眉里的<h1></h1>当正文开头) - 实测数据:含正确
<main></main>的页面,在 VoiceOver 中按M键直达主体的准确率是 100%;缺失时,用户平均需手动下拉 7–12 次才能定位到正文起始
最常被忽略的一点:
<main></main>必须包裹真正对用户有价值的内容,而不是空占位或仅含加载动画。如果主体内容是异步渲染的,得等 DOM 插入后再确保<main></main>已就位——否则屏幕阅读器初始化时就读不到任何主体信息。 - 一个页面只能有一个










