屏幕阅读器不读是正常现象,因其无语义;需用或手动添加role="button"、tabindex="0"等实现可访问性;aria-hidden与display:none隐藏逻辑不同;表单须配label或aria-labelledby;动态内容须用aria-live声明。

屏幕阅读器不读 <div> 是正常现象,不是 bug
<p>HTML 本身没有语义的容器(如 <code><div>、<code><span></span>)默认不会被屏幕阅读器作为可访问节点暴露。这不是冲突,而是规范行为——可访问性依赖的是语义化结构,而非视觉渲染结果。
常见错误现象:<div onclick="submitForm()">提交</div> 看起来能点,但屏幕阅读器既不朗读“按钮”,也不支持空格/回车触发,键盘焦点也无法进入。
- 必须用
<button></button>替代<div> 实现按钮功能 <li>若必须用 <code><div>(如复杂 UI 组件封装),需手动添加 <code>role="button"、tabindex="0"、aria-label,并监听keydown处理 Enter/Space - 仅加
role不加tabindex,元素仍无法获得键盘焦点 -
display: none和visibility: hidden会隐式触发aria-hidden="true"效果,但不可靠——某些旧版 JAWS 仍可能读取visibility: hidden内容 -
aria-hidden="true"不影响布局,display: none会影响盒模型;混用易导致焦点陷入“隐藏却可聚焦”的死区 - 图标+文字组合中,仅对装饰性图标加
aria-hidden="true";纯图标按钮必须配aria-label或aria-labelledby -
for属性值必须与对应控件的id完全一致,大小写敏感 - 用
aria-label虽简单,但无法被翻译工具提取,也不支持 CSS 伪元素内容,多语言站点慎用 - 隐藏的
<label></label>(如position: absolute; clip: rect(0 0 0 0))仍有效,比aria-label更健壮 - 不要给整个页面容器加
aria-live,会导致大量无关变化被朗读 -
aria-live区域需有稳定 DOM 节点,避免频繁销毁重建;推荐复用固定容器,只更新其 innerHTML - 配合
aria-atomic="true"可强制整块重读(如替换整个错误消息),否则可能只读新增/变更部分,造成语义断裂
aria-hidden="true" 和 display: none 的隐藏逻辑完全不同
两者都会让内容不显示,但对屏幕阅读器的影响截然不同:前者主动声明“忽略此节点及其所有子节点”,后者由浏览器自动推断“不可见即不可访问”。问题常出在误用组合。
典型踩坑场景:模态框关闭时用 display: none 隐藏,但未同步移除 aria-hidden="false" 或未重置 aria-modal;或对图标用 aria-hidden="true" 却忘了给其旁的文字补充 aria-label。
表单控件没配 label 或 aria-labelledby 就等于没写
屏幕阅读器依赖明确的标签关联来播报控件用途。缺失标签的 <input type="text"> 可能只读作“编辑文本”,用户完全不知该填什么。
使用 PptxGenJS 和 Python 解析,将结构化的 HTML/CSS 幻灯片内容转换为原生、可编辑的 PowerPoint(.pptx)演示文稿。
使用场景差异明显:<label for="id"></label> 适合标签在视觉上分离的情况;aria-labelledby="id1 id2" 更适合动态生成或跨区域组合标签(如表格中某列标题 + 单元格内提示文本)。
动态内容更新不发 aria-live,屏幕阅读器就当它没发生
AJAX 加载结果、表单校验提示、通知气泡这些不刷新页面的内容变更,屏幕阅读器默认静默处理。必须显式声明实时区域,否则用户卡在旧状态里。
参数选择直接影响体验:aria-live="polite" 适合非紧急信息(如搜索结果数);aria-live="assertive" 会中断当前播报,仅用于错误警告等强打断场景。
aria-live 的协同——比如弹出提示后没把键盘焦点移到提示框,或关闭模态框后焦点丢失到 body。这些细节不写测试很难发现,但用户一用就卡住。










