结论:不能靠“隐藏”来控制辅助设备可访问性信息的展示,而要靠“精准标记”和“语义意图匹配”。display: none或visibility: hidden会彻底切断屏幕阅读器通路;aria-hidden="true"仅屏蔽辅助技术但保留焦点与dom活性,易引发可访问性崩溃;hidden属性才是语义级开关,仅当内容对所有人(视觉用户、辅助技术用户、搜索引擎)本不该存在时才使用。

什么时候该用 hidden 属性?
仅当内容对所有人(视觉用户 + 辅助技术用户 + 搜索引擎)都**本不该存在**时才用。hidden 是语义级开关:元素不渲染、不读取、不聚焦、不提交、不索引。
- ✅ 合理场景:
<input type="hidden" name="csrf_token">、服务端预渲染但客户端暂不需要的占位区块、未激活的模态框主体 - ❌ 错误场景:为图标按钮加
<span hidden>删除</span>——这会让屏幕阅读器完全读不到操作含义 - ⚠️ 坑点:
<div hidden> 在 SSR 页面中若 JS hydration 慢,会闪现再消失;必须加 CSS 兜底:<code>[hidden] { display: none !important; }怎么让文字“看不见但读得着”?
这是最常被搞错的一环:目标不是“隐藏”,而是“视觉移出视口但保留在可访问性树中”。W3C 推荐的最小安全组合是:
visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }- 必须保留
width和height为非零值,否则某些读屏器(如旧版 JAWS)会跳过 - 别用
clip-path: inset(50%)单独替代 —— Safari 15.4 之前不支持,需加@supports回退 - 绝对定位若遇上
overflow: hidden的父容器,内容会被裁掉,得检查层级和容器样式
aria-hidden="true"的唯一安全用法aria-hidden不是隐藏工具,是“辅助技术过滤器”。它只影响可访问性树,不影响视觉、布局、焦点或 JS 行为。- ✅ 安全场景:纯装饰性 SVG 图标(
<svg aria-hidden="true"></svg>)、模态框开启时给背景区域加aria-hidden="true"防止误读 - ❌ 绝对禁止:
<button aria-hidden="true">提交</button>—— 键盘用户仍能 Tab 进去,但读屏器读不到,造成语义断裂 - ⚠️ 坑点:同时写
aria-label="关闭"和子元素<span class="visually-hidden">关闭</span>,会导致重复播报;aria-label会覆盖所有子内容
表单控件和按钮的可访问性隐藏陷阱
按钮、输入框这类可交互元素,隐藏逻辑必须同步处理三件事:视觉、焦点、语义。缺一不可。
- 用
display: none隐藏按钮?它确实不可见也不可点,但若 JS 动态显示时没手动focus(),键盘用户就卡在上一个可聚焦元素 - 用
opacity: 0+pointer-events: none?视觉透明且禁用点击,但默认仍可被 Tab 到——必须额外加tabindex="-1" - 正确做法:优先用
hidden控制初始状态;JS 显示后,立刻el.focus()并确保aria-expanded或aria-hidden状态同步更新
- 必须保留











