应使用语义化html标签替代div/span:标题用h1–h6、段落用p、列表用ul/ol+li、按钮用button、链接用a;role="button"仅声明角色,不提供原生交互逻辑;aria-label用于无文本元素,aria-labelledby复用可见文本,aria-describedby关联辅助说明;表格须用th及scope/headers确保行列关系。

screen reader 读不出 里的内容,该用什么标签替代
因为 <div> 和 <code><span></span> 是纯容器,没有语义,屏幕阅读器默认跳过或仅朗读文本,不提示结构角色。要让辅助技术理解内容意图,得用带语义的 HTML 标签。
常见替换方案:
- 标题用
<h1></h1>–<h6></h6>,别用 <div class="title"> + CSS 改样式
<li>段落用 <code><p></p>,不是 <div> 套文字
<li>列表必须用 <code><ul></ul>/<ol></ol> + <li>,不能靠 <div> 模拟
<li>按钮行为优先用 <code><button></button>,链接用 <a href></a>,避免 <div onclick>
<p>错误示例:<code><div onclick="submitForm()">提交</div> → 屏幕阅读器读作“提交”,不说明这是可交互控件,也无法用空格/回车触发。
role="button" 和原生
加 role="button" 只是告诉屏幕阅读器“这看起来像按钮”,但不自带键盘交互逻辑(比如空格/回车响应、焦点管理、禁用状态样式)。原生 <button></button> 自动支持所有这些。
立即学习“前端免费学习笔记(深入)”;
除非有极特殊样式限制(如必须用 <span></span> 嵌套多层 SVG),否则直接用 <button></button> 更可靠。
如果真要用 role="button",必须手动补全:
- 加
tabindex="0" 让它能被键盘聚焦
- 监听
keydown 事件处理 Enter 和 Space
- 设置
aria-disabled="true" 并配合 CSS 控制视觉状态
- 确保
focus 时有可见轮廓(别用 outline: none 且不替换)
aria-label、aria-labelledby、aria-describedby 怎么选
三者都用于补充可访问性文本,但触发时机和用途不同:
-
aria-label:当元素本身没可见文本(如纯图标按钮),直接给一个简短说明,例如 <button aria-label="关闭"><i class="icon-x"></i></button>
-
aria-labelledby:指向页面中**已有可见文本**的 ID,复用内容,适合表单组合(如 <label id="search-label">搜索</label> + <input aria-labelledby="search-label">)
-
aria-describedby:指向辅助说明文本(如错误提示、格式要求),会在主内容后朗读,适合 <input aria-describedby="hint-id"> 配合 <div id="hint-id">请输入邮箱格式</div>
容易踩的坑:同时用 aria-label 和内部文本,会导致重复朗读;用 aria-labelledby 指向不存在的 ID,屏幕阅读器会静默跳过。
表格没表头,NVDA/JAWS 为什么读成“空白行”
没有 <th> 或缺失 <code>scope/headers 属性时,屏幕阅读器无法建立行列关联,只能逐单元格读数字坐标(如“第2行第3列”),用户根本不知道这列代表“价格”还是“库存”。
修复方式取决于表格复杂度:
- 简单表:每列用
<th scope="col">,每行首列用 <code><th scope="row">
<li>合并表头:用 <code><th id="a"> + <code><td headers="a"> 显式绑定
<li>避免用 <code><div> 模拟表格,CSS Grid/Flex 不会被识别为表格结构
<p>注意:即使视觉上隐藏了表头(如用 <code>visually-hidden 类),只要 DOM 中存在且正确标记,屏幕阅读器仍能读取。
语义化不是加几个 aria- 属性就完事——核心是让 HTML 结构本身承载意义。很多问题出在“先写完视觉再补无障碍”,结果发现 <div> 套三层后,加 <code>role 和 aria 已经救不回交互逻辑和焦点流了。
因为 <div> 和 <code><span></span> 是纯容器,没有语义,屏幕阅读器默认跳过或仅朗读文本,不提示结构角色。要让辅助技术理解内容意图,得用带语义的 HTML 标签。
常见替换方案:
- 标题用
<h1></h1>–<h6></h6>,别用<div class="title"> + CSS 改样式 <li>段落用 <code><p></p>,不是<div> 套文字 <li>列表必须用 <code><ul></ul>/<ol></ol>+<li>,不能靠<div> 模拟 <li>按钮行为优先用 <code><button></button>,链接用<a href></a>,避免<div onclick> <p>错误示例:<code><div onclick="submitForm()">提交</div>→ 屏幕阅读器读作“提交”,不说明这是可交互控件,也无法用空格/回车触发。role="button" 和原生
加
role="button"只是告诉屏幕阅读器“这看起来像按钮”,但不自带键盘交互逻辑(比如空格/回车响应、焦点管理、禁用状态样式)。原生<button></button>自动支持所有这些。立即学习“前端免费学习笔记(深入)”;
除非有极特殊样式限制(如必须用
<span></span>嵌套多层 SVG),否则直接用<button></button>更可靠。如果真要用
role="button",必须手动补全:- 加
tabindex="0"让它能被键盘聚焦 - 监听
keydown事件处理Enter和Space - 设置
aria-disabled="true"并配合 CSS 控制视觉状态 - 确保
focus时有可见轮廓(别用outline: none且不替换)
aria-label、aria-labelledby、aria-describedby 怎么选
三者都用于补充可访问性文本,但触发时机和用途不同:
-
aria-label:当元素本身没可见文本(如纯图标按钮),直接给一个简短说明,例如<button aria-label="关闭"><i class="icon-x"></i></button> -
aria-labelledby:指向页面中**已有可见文本**的 ID,复用内容,适合表单组合(如<label id="search-label">搜索</label>+<input aria-labelledby="search-label">) -
aria-describedby:指向辅助说明文本(如错误提示、格式要求),会在主内容后朗读,适合<input aria-describedby="hint-id">配合<div id="hint-id">请输入邮箱格式</div>
容易踩的坑:同时用
aria-label和内部文本,会导致重复朗读;用aria-labelledby指向不存在的 ID,屏幕阅读器会静默跳过。表格没表头,NVDA/JAWS 为什么读成“空白行”
没有
<th> 或缺失 <code>scope/headers属性时,屏幕阅读器无法建立行列关联,只能逐单元格读数字坐标(如“第2行第3列”),用户根本不知道这列代表“价格”还是“库存”。修复方式取决于表格复杂度:
- 简单表:每列用
<th scope="col">,每行首列用 <code><th scope="row"> <li>合并表头:用 <code><th id="a"> + <code><td headers="a"> 显式绑定 <li>避免用 <code><div> 模拟表格,CSS Grid/Flex 不会被识别为表格结构 <p>注意:即使视觉上隐藏了表头(如用 <code>visually-hidden类),只要 DOM 中存在且正确标记,屏幕阅读器仍能读取。语义化不是加几个
aria-属性就完事——核心是让 HTML 结构本身承载意义。很多问题出在“先写完视觉再补无障碍”,结果发现<div> 套三层后,加 <code>role和aria已经救不回交互逻辑和焦点流了。
- 加









