前端开发中的无障碍化(Accessibility)经常被放到项目末期补,结果就是表单组件对屏幕阅读器不友好、键盘用户无法完成操作。表单是网站与用户交互最密集的组件,表单无障碍化直接影响可访问性评分和实际使用体验。本文从语义化结构、ARIA属性、键盘导航三个层面,说明如何把一套普通表单改造成符合WCAG 2.1 AA标准的无障碍表单。
表单语义化与标签关联
无障碍表单的第一步是用对语义元素。原生label标签的for属性与控件id关联后,屏幕阅读器能读出字段名,点击标签也能聚焦输入框,这是成本最低、收益最稳定的做法:
<form id="register-form" novalidate>
<div class="field">
<label for="username">用户名</label>
<input type="text" id="username" name="username"
autocomplete="username" required aria-required="true" />
</div>
<div class="field">
<label for="email">邮箱地址</label>
<input type="email" id="email" name="email"
autocomplete="email" required aria-required="true" />
</div>
<div class="field">
<fieldset>
<legend>性别(选填)</legend>
<label><input type="radio" name="gender" value="male" />男</label>
<label><input type="radio" name="gender" value="female" />女</label>
</fieldset>
</div>
</form>
radio按钮组必须用fieldset+legend包裹,legend会作为整个组的可访问名称被朗读。不要用placeholder代替label,placeholder在输入内容后消失,屏幕阅读器无法读取,而且颜色对比度通常不足。
错误提示的ARIA实现与实时通知
表单校验失败时,错误信息必须能被辅助技术感知。做法是给错误文本容器加上aria-live=”assertive”或role=”alert”,校验失败时把错误写入该容器,读屏软件会立即朗读;同时用aria-invalid标记出错字段:
<div class="field">
<label for="username">用户名</label>
<input type="text" id="username" name="username"
required aria-required="true"
aria-invalid="true"
aria-describedby="username-error" />
<p id="username-error" class="error" role="alert">
用户名不能为空,且长度在4到20个字符之间
</p>
</div>
aria-invalid=”true”让读屏提示”输入无效”,aria-describedby把错误文本挂到输入框上。表单顶部还可以放一个错误汇总区,用role=”alert”列出所有出错字段,方便键盘用户与读屏用户快速定位。
键盘导航与焦点管理
自定义组件(下拉选择、日期选择、评分控件)是最容易破坏键盘操作的区域。一个可用性规则是:所有交互元素必须能仅用键盘完成。下拉选择器按组合框模式实现,焦点落在输入框时按方向键切换选项,Enter确认,Esc关闭:
class CustomSelect extends HTMLElement {
connectedCallback() {
this.input = this.querySelector('input[role="combobox"]');
this.listbox = this.querySelector('[role="listbox"]');
this.options = [...this.querySelectorAll('[role="option"]')];
this.input.addEventListener('keydown', (e) => {
switch (e.key) {
case 'ArrowDown': e.preventDefault(); this.moveFocus(1); break;
case 'ArrowUp': e.preventDefault(); this.moveFocus(-1); break;
case 'Enter':
if (this.open) {
e.preventDefault();
this.selectFocused();
}
break;
case 'Escape':
if (this.open) { this.closeListbox(); }
break;
}
});
}
}
焦点管理的关键是焦点不能丢失:弹层打开时焦点进入弹层,关闭时焦点回到触发控件。错误场景中,提交失败后应把焦点移到第一个错误字段,而不是停留在提交按钮。
动态区域与表单状态的无障碍提示
表单里常见的”提交中”、”保存成功”这类状态变化,视觉用户看得到,读屏用户可能毫无感知。动态区域用aria-live声明后,内容变化会自动被朗读:
<div id="form-status" aria-live="polite" aria-atomic="true" class="sr-only"></div>
<script>
const status = document.getElementById('form-status');
submitBtn.addEventListener('click', async () => {
status.textContent = '正在提交,请稍候';
submitBtn.disabled = true;
try {
await api.submit(formData);
status.textContent = '提交成功';
} catch {
status.textContent = '提交失败,请检查错误提示';
focusFirstError();
} finally {
submitBtn.disabled = false;
}
});
</script>
aria-live=”polite”适合非紧急信息,错误汇总与超时提示用assertive。注意live区域初始应为空,避免页面加载时把不需要的信息朗读出来。按钮禁用状态通过disabled属性标记,读屏会提示”不可用”,同时提交期间再次点击也不会重复提交。
无障碍表单的验证与测试方法
改造完成后用自动化与手动两种方式验证。自动化用axe-core接入CI,每次提交都跑一遍规则检测:
// 在Playwright测试中加入axe检测
const axe = require('@axe-core/playwright');
test('注册表单无严重无障碍问题', async () => {
await page.goto('/register');
const results = await new axe.AxeBuilder({ page }).analyze();
const critical = results.violations.filter(
v => v.impact === 'critical' || v.impact === 'serious'
);
expect(critical).toHaveLength(0);
});
手动验证不能省:关掉鼠标,只用键盘把表单完整走一遍;再开屏幕阅读器(Windows用NVDA,macOS用VoiceOver)从标签到错误提示逐个字段听。这两步通过后,再把表单实际交给使用辅助技术的用户试用一轮,基本就能达到WCAG 2.1 AA。
无障碍不是可选项,表单无障碍化涉及的标签关联、ARIA错误提示、键盘导航与aria-live状态通知,每一层都直接影响真实用户能否完成操作。按组件逐一落地并用axe加手动键盘验证,表单的可访问性就能达到可靠水平。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/qian-duan-biao-dan-wu-zhang-ai-hua-shi-zhan-cong-aria-biao/