必填字段星号须为真实文本节点,错误消息需用aria-invalid与role="alert"标识,禁用状态必须用原生disabled属性,加载中状态依赖aria-busy与aria-live。

必填字段的星号必须是真实文本节点
屏幕阅读器读不出伪元素生成的 *,哪怕它看起来再红、再醒目。常见错误是用 label.required::after { content: "*"; },这会导致语音朗读跳过星号,用户完全感知不到“必填”含义。
正确做法是把星号写进 label 的文本内容里,例如:<label>邮箱*</label>。这样 VoiceOver、NVDA 都会自然读作“邮箱星号”,停顿合理、语义完整。
- 别用空格+星号(如
邮箱 *),中间停顿生硬,影响听感 - 如果 label 文本来自 i18n 多语言系统,星号必须随翻译一起注入,不能 JS 后加——否则 aria-label 或 DOM 更新不同步
- 用 CSS 控制颜色、大小、垂直对齐即可:
label.required > * { color: #d32f2f; font-size: 0.8em; vertical-align: super; },但绝不能用display: none或visibility: hidden
错误状态不能只靠红色边框
仅靠 border-color: #f44336 标识验证失败,对色觉障碍用户无效,也绕过了辅助技术的语义识别。浏览器不会把红色边框自动映射为“错误”角色。
真正起作用的是 aria-invalid="true" 和配套的 aria-describedby 指向错误消息元素。视觉样式只是同步呈现,不是替代方案。
- input 必须同时设置:
aria-invalid="true"+aria-describedby="error-email" - 错误消息元素(如
<div id="error-email">邮箱格式不正确</div>)需用role="alert"或aria-live="assertive"确保即时播报 - CSS 中的红色边框、背景、图标都只是强化层;删掉它们,只要 ARIA 属性在,屏幕阅读器仍能准确传达错误
禁用状态要同步语义与行为
disabled 属性本身已自带可访问语义:键盘无法聚焦、屏幕阅读器会读作“禁用”,且原生阻止交互。但很多人用 opacity: 0.5 + pointer-events: none 模拟禁用,这是危险的。
这种“视觉禁用”在辅助技术中仍是可聚焦、可操作的,用户可能反复尝试点击或按回车,却得不到任何反馈。
- 永远优先用原生
disabled属性,而不是 CSS 模拟 - 若需兼容旧版 IE 或特殊交互逻辑,必须手动补全:
tabindex="-1"+aria-disabled="true"+ 移除所有事件监听 - 禁用按钮的
type也要明确,比如<button type="button" disabled></button>,避免浏览器默认为 submit 导致意外提交
加载中状态得让屏幕阅读器感知到
仅用旋转图标或 cursor: wait,对盲人用户毫无意义。他们需要知道“当前操作未完成”,而不是盯着一个动效猜进度。
关键不是“看起来在加载”,而是“被明确告知正在处理”。这依赖 aria-busy="true" 和动态更新的 aria-live 区域。
- 给操作区域(如表单、按钮父容器)加
aria-busy="true",完成后设为false - 配合
<div aria-live="polite" aria-atomic="true"></div>输出文字提示,如“正在提交,请稍候” - 按钮内文字可改为“提交中…”并加
aria-disabled="true",防止重复点击;但不要移除disabled属性——两者共存更稳妥
真实可访问的状态标识,从来不是“加点颜色”或“换个图标”就能解决的。它要求你把每个视觉变化,都对应到一个可被辅助技术解析的语义信号上。漏掉任意一环,对某些用户来说,就是整个功能不可用。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











