上一篇文章介绍了一些帮助开发者创建无障碍应用程序的工具。表单是许多应用程序的一个常见部分,它们必须是无障碍的,以便许多不同的人可以有效地使用它们。这篇文章涵盖了关于创建无障碍React表单的几个要点。

一个无法访问的表单
这是一个有几个可访问性问题的表单:
export function InaccessibleForm() {
...
return (
<form className="inaccessible-form" ...>
<div className="inaccessible-field">
<label>Name</label>
<input type="text" ... />
{errors.name && <div className="error">You must enter your name</div>}
</div>
<div className="inaccessible-field">
<label>User code</label>
<div className="user-code-field">
<input type="text" ... />
<span className="user-code-help">Enter your 4 digit user code</span>
</div>
{errors.userCode && (
<div className="error">You must enter your 4 character user code</div>
)}
</div>
<div className="inaccessible-field">
<div id="level-label">Level</div>
<select ...>
...
</select>
{errors.level && <div className="error">You must enter your level</div>}
</div>
<div className="inaccessible-field">
<label>Notes</label>
<textarea ... />
{errors.notes && <div className="error">You must enter some notes</div>}
</div>
<div className="inaccessible-field">
<input type="checkbox" />
<label>Agree</label>
</div>
<button type="submit">Submit</button>
</form>
);
}
当一个字段编辑器获得焦点时,屏幕阅读器不会读出上述表单中的字段标签。这使得盲人用户很难理解在每个字段中应该输入什么。
此外,屏幕阅读器也不会读出出现的验证错误信息。因此,盲人用户不会知道他们在某个字段中输入了错误的内容。
标签和验证错误信息在视觉上也不是很清晰。这使得视力不佳的用户很难理解这个表格。
下面是一张表单的截图。
将字段标签与编辑器联系起来
为了让屏幕阅读器在编辑器获得焦点时能够阅读字段标签,标签必须与编辑器相关联。有几种方法可以做到这一点。
典型的方法是通过label htmlFor 道具(在DOM中是for 属性)来引用编辑器id :
<label htmlFor="name">Name</label>
<input id="name" type="text" ... />
也可以反过来,用编辑器的aria-labelledby 道具进行关联。当标签不是一个label 元素时,这很有用:
<div id="level-label">Level</div>
<select aria-labelledby="level-label">
...
</select>
这种关联也可以通过将编辑器周围的label 元素包裹起来:
<label>
<input type="checkbox" />
Agree
</label>
将字段标签与编辑器相关联的另一个好处是,用户可以点击标签来将焦点设置到表单控件上。此外,点击复选框或单选按钮字段上的标签可以切换选中状态。这在小屏幕上很有帮助,特别是针对小的复选框和单选按钮时。
不错!☺️
将一个编辑器与信息文本联系起来
有时,除了标签之外,一个字段还有额外的信息文本。如果该元素与编辑器相关联,当编辑器获得焦点时,屏幕阅读器将读取它。
编辑器上的aria-describedby ,可以用来将它与包含更多信息的元素联系起来:
<label htmlFor="userCode">User code</label>
<div ...>
<input
id="userCode"
type="text"
aria-describedby="user-code-help" ...
/>
<span id="user-code-help" ...> Enter your 4 digit user code
</span>
</div>
在上面的例子中,当input 元素获得焦点时,屏幕阅读器将读出 ***"输入你的4位数用户代码"***除了标签之外,还有 "用户代码".
请注意,这种方法比使用placeholder 道具更可取,因为:
- 屏幕阅读器对
aria-describedby的支持比placeholder好得多。 - 占位指示可能在视觉上不适合方框,就像我们的例子。
- 当用户开始输入时,占位指示就会消失。
为字段添加自动完成功能
在与其他表单有共同数据的字段上添加自动完成功能,可以让用户使用他们之前提交的数值立即填充这些字段。这对普通用户来说是一个很好的节省时间的方法,对有运动障碍的人特别有帮助。
自动完成可以用autoComplete 道具来控制(渲染为autocomplete 属性),并且可以在input 、select 和textarea 元素上使用:
<input
id="name"
type="text"
autoComplete="name" ...
/>
将autoComplete 设置为"name" 值,意味着浏览器将提示以前在表单中填写过的全名。
将一个编辑器标记为必填项
示例表格中的所有字段都是必填的,但从视觉上看,没有任何迹象表明是这样的。此外,屏幕阅读器也不会意识到这些字段是必填的。
我们将在标签后面使用一个*****作为视觉上的必填指标:
<label htmlFor="name">
Name
<i aria-hidden="true">*</i></label>
我们在星形元素上使用了aria-hidden ,这样屏幕阅读器就不会宣布这个词了 "星".相反,我们希望屏幕阅读器能够宣布 "必填"- 我们在编辑器元素上使用了aria-required="true" :
<input
...
aria-required="true" />
注意,我们没有使用required ,因为这将导致浏览器验证该字段,而我们想控制验证(在这个例子中借助React Hook Form)。
将一个编辑器标记为无效
使用aria-invalid ,一个字段的编辑器可以被标记为有效或无效。将其设置为"true" ,意味着该字段是无效的,而将其设置为"false" ,意味着它是有效的:
<input
id="name"
type="text"
aria-invalid={errors.name ? "true" : "false"} {...register("name", { required: true })}
/>
这个例子中的表单使用了React Hook Form,所以如果一个字段处于errors 的状态,它就是无效的。
当设置为aria-invalid="true" ,该字段获得焦点时,屏幕阅读器会说它是无效的。
可访问的内联验证错误信息
要让屏幕阅读器读取验证错误,有几件事要做:
- 为了让屏幕阅读器在DOM中首次呈现时宣布错误,包含错误信息的元素需要包含
role=alert。 - 为了让屏幕阅读器在无效字段编辑器拥有焦点时宣布错误,该编辑器需要与错误信息元素相关联。这种关联是通过引用字段编辑器中的错误信息ID来实现的
aria-describedby道具。
下面是我们表单中的一个示例字段:
<input
...
aria-describedby="name-error" />
{errors.name && (
<div
id="name-error" role="alert" ... >
You must enter your name
</div>
)}
aria-describedby 可以通过列出由空格分隔的所有错误信息元素ID来引用多个错误信息元素。
一个有趣的情况是,当aria-describedby 用于附加信息时,比如我们表单中的用户代码字段。我们可以同时引用附加信息和错误信息元素,用空格隔开。然而,屏幕阅读器会读出这两条信息,这可能是不可取的。在我们的例子中,我们只在出现错误时引用错误信息;否则,我们就引用说明:
<div className="user-code-field">
<input
id="userCode"
...
aria-describedby={errors.userCode ? "user-code-error" : "user-code-help"} />
<span id="user-code-help" className="user-code-help"> Enter your 4 digit user code
</span>
</div>
{errors.userCode && (
<div id="user-code-error" role="alert" className="error"> You must enter your 4 character user code
</div>
)}
无障碍的文本颜色对比
无障碍性的另一部分是视觉方面。例如,文本需要清晰可见。这意味着文本的颜色需要与它的背景有一定程度的对比。
网页可及性网站上的这个页面详细介绍了如何在Chrome DevTools中检查文本颜色对比。这个工具证实了字段标签没有通过该检查。
将表格中的文字变得更深一些,标签变得更粗一些,使表格在视觉上更清晰:
form.accessible-form {
...
color: #555555;
}
form .field label {
...
font-weight: 600;
}
可访问的焦点指示器
焦点指示器是一个视觉指示器,显示哪个元素当前拥有焦点。这对键盘用户来说是至关重要的。
许多应用程序删除了焦点指示器,就像我们的无障碍表单的例子:
form .inaccessible-field input:focus {
outline: none;
}
键盘用户会发现填写我们的无障碍表单是个挑战,因为不容易知道哪个字段有焦点。所以,我们应该避免像上面的例子那样删除焦点指示器。
浏览器对键盘用户的元素轮廓有一个默认的样式。然而,焦点指示器必须是清晰可见的。这意味着与相邻元素有足够高的颜色对比--不幸的是,浏览器默认的焦点指示器可能无法满足这一要求。😞
Sara Soueidan有一篇关于焦点指示器的可访问性要求的好文章。
focus-visible 伪类允许我们在元素被聚焦时设置一个可访问的轮廓:
form .field input:focus-visible {
outline: 2px solid #737373;
outline-offset: 2px;
}
form.accessible-form button[type="submit"]:focus-visible {
outline: 2px solid #11683f;
outline-offset: 2px;
}
focus-visible 伪类比focus 要好,因为它只适用于键盘用户。例如,如果用户用鼠标点击提交按钮,轮廓不会被应用于focus-visible 伪类,但会被应用于focus 。
这就是了。现在的表单更容易访问了!😊
这篇文章的代码可以在Codesandbox中找到,链接如下: