QualiBooth

guides

当错误提示把用户拒之门外

无障碍错误提示不只是加几个 ARIA 属性那么简单。本文讲解要让错误提示对所有人可用,究竟需要做什么。

1 min read QualiBooth
屏幕上的网页登录表单,显示输入框和登录按钮,代表网页表单的无障碍性。

表单出错的那一刻

想象这样的场景:一位盲人用户填完结账表单,点击提交,屏幕阅读器却没有播报任何有用的信息。没有提示,没有解释。页面已经用红色在视觉上标出了五个验证错误,但用户对此一无所知。他再次点击提交。又一次。最终,他离开了。

这并不是什么罕见场景。不可访问的错误处理是我们在真实审计中发现的最常见障碍之一,而且它往往在最糟糕的时刻让用户受挫——正当他们试图完成交易或提交重要内容的时候。

好消息是,修复它在很大程度上只是一个”知道什么才算好”的问题。失败的模式几乎总是那几种。

为什么错误提示对辅助技术用户如此困难

视力正常的鼠标用户往往能立刻注意到验证错误——红色边框、警告图标、出现在输入框下方的文字。但依赖屏幕阅读器、键盘导航或语音控制的用户,面对的是一种根本不同的体验。

当表单提交后出现错误时:

  • 屏幕阅读器用户可能什么都听不到,除非焦点移动到错误处,或有实时区域进行播报
  • 键盘用户需要能够通过键盘触达每条错误提示,并理解它属于哪个字段
  • 语音控制用户需要通过可见且准确的标签来定位字段——如果标签错误或缺失,他们就会卡住

这一切都不会自动发生。你必须自己构建。

适用的 WCAG 标准

WCAG 2.2 中有四条成功标准直接涵盖错误处理:

3.3.1 错误识别(A 级)——如果自动检测到错误,必须以文本形式向用户标识并描述出错的项目。不能只通过颜色来传达错误。

3.3.2 标签或说明(A 级)——要求特定格式的输入项,必须在输入之前或输入过程中说明该要求,而不是等到提交失败之后。

3.3.3 错误建议(AA 级)——如果检测到错误且已知修正建议,就应当提供。“日期无效”是不够的,“请按 DD/MM/YYYY 格式输入日期”才可以。

3.3.4 错误预防(AA 级)——对于后果重大的提交(金融交易、法律协议),必须让用户在操作不可撤销之前,有机会检查、修正并确认。

此外还有 4.1.3 状态消息(AA 级),它涵盖不接收焦点的动态注入消息——这些消息必须通过 role="status"role="alert" 由辅助技术播报。

一条无障碍错误提示到底需要什么

要把错误提示做好,需要关注四个不同的层面:

1. 程序化关联

每条错误提示都必须通过 aria-describedby 与其字段绑定。这会告诉屏幕阅读器在字段获得焦点时播报错误文本。

<!-- Before: error text exists visually but is invisible to screen readers -->
<label for="email">Email</label>
<input type="email" id="email" class="error">
<p class="error-text">Enter a valid email address.</p>

<!-- After: programmatic association via aria-describedby -->
<label for="email">Email address</label>
<input
  type="email"
  id="email"
  aria-describedby="email-err"
  aria-invalid="true"
>
<p id="email-err" class="error-text">Enter a valid email address.</p>

aria-invalid="true" 属性表明该字段当前无效,大多数屏幕阅读器会在焦点落到该字段时播报这一状态。

2. 提交后的焦点管理

当表单提交后存在错误时,焦点必须移动到一个有用的位置。最常见的两种模式是:

  • 将焦点移动到表单顶部的错误摘要,其中列出所有错误并链接到对应字段
  • 将焦点移动到第一个出错的字段

如果焦点停留在提交按钮上,或者根本没有移动,屏幕阅读器用户就只能自己在表单中逐项摸索错误——前提是他们知道有错误存在。

// After validation fails, move focus to the error summary
const summary = document.getElementById('error-summary');
summary.setAttribute('tabindex', '-1');
summary.focus();

3. 动态错误的实时区域播报

对于在用户输入过程中出现的错误(内联实时验证),请使用 ARIA 实时区域,让消息无需移动焦点即可被播报。

<p role="alert" aria-live="assertive" id="password-err">
  Password must be at least 8 characters.
</p>

对于需要立即处理的错误,使用 role="alert" / aria-live="assertive";对于可以等用户停顿后再播报的次要反馈,使用 role="status" / aria-live="polite"

4. 错误提示本身

措辞很重要。无障碍的错误提示应当是:

  • 具体的:说明哪里出了问题,而不只是说出了问题
  • 可操作的:明确告诉用户该怎么做才能修复
  • 礼貌的:避免”你输入了无效值”之类的指责性语言
不可访问可访问
”输入无效""电子邮件地址必须包含 @ 符号,例如 name@example.com"
"错误""日期必须为 DD/MM/YYYY 格式"
"必填字段""请填写全名"
"密码无效""密码必须至少 8 个字符,并包含一个数字”

不同错误场景的模式

内联字段错误

最常见的模式。错误提示直接显示在对应字段的下方。适用于简单表单。需要 aria-describedbyaria-invalid 才能被正确播报。

错误摘要横幅

对于存在多个错误的长表单,在顶部放置一个摘要,以链接形式列出所有问题并跳转到对应字段。提交失败后将焦点移动到这里。这是 GOV.UK 采用的模式,也被广泛推荐用于复杂表单。

Toast 通知

出现在屏幕边缘、短暂存在的消息,是常见模式中无障碍性最差的一类。它们在屏幕阅读器用户触达之前就消失了,往往根本不会被播报,也不提供任何恢复路径。避免用 Toast 来展示错误。如果一定要使用,请让表单本身同时保持一个持久的错误状态。

系统错误

当服务器端出现问题时,请用通俗的语言告诉用户发生了什么,以及接下来可以做什么。只说”出了点问题”而不给任何进一步指引,会让用户束手无策。

<div role="alert" aria-live="assertive">
  <p>We couldn't save your changes due to a network error.
  Please check your connection and try again.</p>
</div>

测试核对清单

实现错误处理之后,请手动验证以下各项——自动化工具无法捕捉其中的大部分:

  • 提交一个空的必填表单后,焦点会移动到错误摘要或第一个出错的字段
  • 每条错误提示都通过 aria-describedby 与其字段关联
  • 出错的字段带有 aria-invalid="true"
  • 焦点落到受影响的字段时,错误提示会被播报
  • 实时验证使用了实时区域
  • 错误提示使用具体、可操作的措辞——而不只是”无效”
  • 颜色不是标示错误的唯一方式(红色之外还有图标或文字标签)
  • 可以通过键盘 Tab 键导航到错误处
  • 提交后的焦点顺序合乎逻辑,不会不可预测地跳转
  • Toast 消息配有持久的错误状态

为什么自动化工具漏掉了其中大部分

自动化扫描工具可以检查 aria-describedby 是否指向一个存在的元素,以及 aria-invalid 是否存在。但它无法检查提交后焦点是否正确移动、错误文本是否准确,或者 Toast 通知是否在被读到之前就消失了。我们的人工无障碍审计包含使用真实辅助技术进行的表单专项测试——这是端到端验证错误处理是否真正有效的唯一可靠方式。

如果你不确定自己的表单处于什么水平,可以先运行免费扫描找出可自动检测的问题,再逐步深入。

在用户之前发现表单的无障碍问题