标准答案
- 搜索框和弹窗的可访问性不能只靠 aria,要同时处理语义、焦点、键盘操作、状态反馈和焦点恢复。
- 搜索框要有可访问名称,优先用可见 label;搜索按钮要用真实 button,不要用 div 模拟。
- 搜索结果数量、无结果、加载中这类状态变化,可以用 aria-live 给屏幕阅读器做温和提示。
- 弹窗要有明确标题,可以用原生 dialog,或用 role="dialog" 配合 aria-modal。
- 弹窗打开后焦点要进入弹窗,Tab 要限制在弹窗内部,Esc 可以关闭,关闭后焦点要回到触发按钮。
题目解析
- 输入框必须有可访问名称,不要只依赖 placeholder。
- 搜索按钮使用 button,不要用 div 模拟。
- 搜索结果数量或无结果状态可以用 aria-live 做温和提示。
- 键盘用户应能完成输入、提交、清空和跳转结果。
- 打开后焦点移动到弹窗标题、关闭按钮或第一个可操作元素。
- Tab 焦点应限制在弹窗内部,不能跑到背景页面。
- Esc 可以关闭弹窗,关闭后焦点回到打开弹窗的按钮。
- 背景内容要避免被屏幕阅读器继续读到,可以结合 aria-modal 或 inert。
代码示例
原生 dialog 能减少一部分弹窗语义成本,但仍要处理标题、关闭按钮和焦点恢复。
HTML
<button type="button" id="open-search">打开搜索</button>
<dialog aria-labelledby="search-title">
<h2 id="search-title">搜索文章</h2>
<label for="keyword">关键词</label>
<input id="keyword" name="keyword" type="search">
<button type="submit">搜索</button>
<button type="button" value="cancel">关闭</button>
</dialog>常见误区
- 只实现鼠标点击关闭,没有 Esc 和焦点恢复。
- 弹窗打开后焦点仍停留在背景页面。
- 用 div 伪装按钮,缺少键盘触发、焦点样式和语义。
追问方向
- 如果不用原生 dialog,如何实现焦点陷阱?需要记录可聚焦元素,拦截 Tab 和 Shift+Tab。
- aria-label 和 label 有什么区别?可见 label 对所有用户都有帮助,aria-label 主要给辅助技术提供名称。
- 为什么 placeholder 不能替代 label?因为它会消失,也可能被辅助技术处理不一致。