
本文讲解如何在保持 toast 通知可访问性的前提下,确保屏幕阅读器仅朗读关键信息(如标题和内容),而不重复朗读关闭按钮的 aria-label,核心方案是将按钮移出 role="status" 容器。
本文讲解如何在保持 toast 通知可访问性的前提下,确保屏幕阅读器仅朗读关键信息(如标题和内容),而不重复朗读关闭按钮的 `aria-label`,核心方案是将按钮移出 `role="status"` 容器。
在构建无障碍友好的前端 toast 通知时,一个常见挑战是:既要利用 role="status"(等效于 aria-live="polite")实现非侵入式状态播报,又要避免屏幕阅读器将关闭按钮的 aria-label="close" 一并朗读出来——这会导致冗余输出,例如:“Information. Lorem ipsum dolor. Close”,破坏信息焦点。
根本原因在于:只要元素位于 aria-live 区域(或 role="status"/role="alert" 等隐式 live 区域)内部,其所有文本内容(包括按钮的 aria-label)都会被自动纳入朗读流。试图通过 aria-hidden="true" 隐藏按钮虽能阻止朗读,但会同时剥夺键盘和语音控制用户的操作能力,严重违反 WCAG 2.1 原则(尤其是 2.1.1 Keyboard 和 4.1.2 Name, Role, Value),因此不可取。
✅ 正确解法是结构隔离:将交互控件(关闭按钮)置于 live 区域之外,仅让语义化内容容器承担播报职责。重构后的 HTML 结构如下:
<div class="toast-notification">
<button aria-label="Close notification" class="toast-notification__close">
<svg viewbox="0 0 24 24" focusable="false" aria-hidden="true"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path></svg></button>
<div role="status" aria-live="polite" aria-atomic="true">
<div class="toast-notification__title">Information</div>
<div class="toast-notification__text">Lorem ipsum dolor</div>
</div>
</div>
关键改进点:
- 关闭按钮完全脱离
role="status"容器,保留完整键盘可聚焦性(tabindex="0"默认生效)与语音命令可发现性; -
aria-live="polite"显式声明(虽role="status"已隐含,但显式更清晰),配合aria-atomic="true"确保整段内容作为原子单元播报,避免只读标题或只读正文; - SVG 图标添加
aria-hidden="true"和focusable="false",防止其被误读为独立可交互元素; - 按钮
aria-label使用完整短语"Close notification",比单字"close"更具上下文明确性(符合 WCAG 2.1 SC 2.4.6)。
? 注意事项:
- CSS 布局需适配新结构(如使用 Flexbox 或 Grid 调整按钮与内容的视觉位置),但逻辑结构与视觉呈现可完全解耦;
- 若 toast 支持手动关闭且不自动销毁,必须保留按钮的可访问性——此时绝不可用
aria-hidden; - 对于自动关闭的 toast,仍建议保留手动关闭入口,并设置合理停留时长(≥ 5 秒),兼顾低视力、阅读障碍及屏幕阅读器播报完整性需求。
总结:无障碍不是“隐藏什么”,而是“组织什么”。通过语义化 DOM 分层,我们既满足了信息播报的简洁性,又保障了所有用户对交互控件的平等访问权——这才是健壮、合规、以人为本的 toast 实现方式。










