返回探索
指南VibeFix 编辑部更新于 2026年10月10日

别让残障用户用不了你的产品:vibe 项目无障碍(a11y)实战

AI 生成的 UI 从不按 Tab、不开读屏,无障碍问题在它的视觉反馈闭环里全部隐形。这篇实战指南给出 P0/P1/P2 三级优先级清单、四套可直接复制的 prompt 模板、30 分钟免费审计流程,以及 6 组高频翻车代码的 before/after 修法,附上线前验收清单。

无障碍实战指南封面:键盘 Tab 键焦点框与读屏声波交织的示意插画

你的产品可能正在把一部分用户挡在门外

想象这个场景:你用 AI 花两周搓出一个产品,界面漂亮、动效丝滑,朋友试用都说好。然后有一天,一位只用键盘操作电脑的用户打开它——Tab 键按下去,焦点不知道飞去了哪里;一位视障用户打开读屏软件,听到的是一连串"按钮、按钮、按钮",完全分不清每个按钮是干什么的。他们不是"用不惯",而是根本用不了。

这不是危言耸听,而是 vibe coding 时代的一个结构性问题:AI 生成 UI 的反馈闭环是纯视觉的。它看截图、调配色、改布局,但它永远不会按一次 Tab 键,也永远不会打开 VoiceOver 听一遍页面读出来是什么效果。所有需要"非视觉验证"的质量维度,在 AI 的工作流里都是盲区——而无障碍(accessibility,简称 a11y)恰好整个落在盲区里。

我的判断是:AI 编程跳过的不是"细节",而是一整类用户能不能用你的产品的根本问题。好消息是,无障碍的大部分工作是高度模式化的——语义标签、焦点管理、对比度、键盘路径,翻来覆去就是那几十个检查点。这意味着它非常适合被写成清单、写进 prompt、变成发布流程里的一项固定动作。这篇指南就是干这个的:给你一套按优先级排好的清单、能直接复制的 prompt 模板、30 分钟审计流程,以及 AI 代码最常见的翻车代码和修法。

先说清楚边界:这篇不是 WCAG 全文翻译,也代替不了真实残障用户的测试。它的目标很实际——让一个独立开发者在上线前,把最要命的无障碍问题清零。

为什么 AI 生成的 UI 总在无障碍上翻车

先理解病因,再谈药方。AI 写前端代码时,有三个系统性原因让它必然产出无障碍债务:

第一,它的"眼睛"只有截图。你让 AI 改 UI,它看的是渲染结果:对齐了没、配色顺眼不顺眼。焦点框看不见?截图里体现不出来。读屏朗读顺序错乱?截图里没有声音。键盘 Tab 顺序跳来跳去?截图是静态的。所有无障碍问题在视觉反馈里都是不可见的,AI 自然一个都修不到。

第二,它的训练语料里充满了坏榜样。网上教程、demo 项目、问答社区的回答里,<div onClick={...}> 假按钮、* { outline: none } 全局去焦点框、placeholder 冒充 label 的写法比比皆是。AI 学的是"大多数人怎么写",而不是"正确怎么写",于是把坏习惯原样复刻进你的项目。

第三,"能跑"不等于"能用"。AI 的交付标准是"页面渲染出来、功能调通"。但无障碍的交付标准是"换一种输入输出方式依然调得通":只用键盘、只听声音、只能看清高对比度。AI 从不做第二种测试,所以它的"完成"和你的用户的"能用"之间,永远差着一层。

认清这三点,你就会明白:无障碍不能靠"让 AI 自觉",必须靠你把规则写进 prompt、把检查写进流程。AI 是执行力极强的下属,但检查清单得你来定。

P0:上线前必须修,修不好就别上线

下面这 7 条是底线。任何一条没做到,都意味着某一类用户根本用不了你的核心功能。按这个顺序修,投入产出比最高。

1. 用语义化 HTML,别用 div 假装一切

按钮就用 <button>,链接就用 <a>,导航用 <nav>,主内容用 <main>,标题按层级用 h1–h6。语义标签自带键盘行为和读屏语义——button 天然能被 Tab 聚焦、被空格激活、被读屏报出"按钮";而 div onClick 在读屏用户听来只是一段死文字,按键盘也毫无反应。AI 最爱写 div 假按钮,因为"长得一样",但"长得一样"和"用起来一样"之间差了一个宇宙。修法:全局搜索 onClick,凡是挂在 div/span 上的,逐个换成真正的 button 或 a。

2. 焦点状态必须可见,别全局干掉 outline

键盘用户靠焦点框知道自己在哪。很多 AI 生成的 CSS 里藏着 * { outline: none; }——默认的焦点框不好看,AI 就"贴心"地全干掉了。结果:Tab 键按了十几次,页面毫无反应,用户以为网站卡死了。正确做法是保留 :focus-visible 样式:鼠标点击时不显示框(不影响视觉),键盘 Tab 时显示框(保证可用)。这是 P0 里最容易修、影响最大的一条。

3. 图片该有 alt 的要有 alt

规则很简单:传达信息的图片写清楚 alt(比如"2026 年 10 月营收趋势图:从 2 万涨到 8 万"),纯装饰的图片写 alt="" 让读屏直接跳过。AI 常犯两个极端:要么所有图都没 alt,读屏只能报"图片、图片";要么 alt 写成"图片 1""未命名"。修法:让 AI 列出全站的 <img>,逐个补 alt。记住 alt 描述的是图片传达的信息,而不是图片本身长什么样。

4. 颜色对比度达标,且别只用颜色传信息

正文文字对比度至少 4.5:1,大号文字至少 3:1。浅灰文字配白色背景是 AI 的审美重灾区——在高分屏上看是"高级感",在普通屏幕和弱视用户眼里直接隐形。更隐蔽的是"只用颜色传信息":表单报错只把边框变红、图表只用红绿区分涨跌,色盲用户看到的是一片灰。修法:报错同时给出文字和图标,状态同时用颜色加文字或图标表达。用 WebAIM 对比度检查器抽查几组关键配色,5 分钟就有结论。

5. 所有功能键盘可达,没有键盘陷阱

拔掉鼠标,只用 Tab、Shift+Tab、Enter、Space、Esc、方向键,能不能走完注册、下单、发布这条核心路径?下拉菜单、日期选择器、日历、富文本编辑器是重灾区——AI 接的第三方组件常常键盘不可操作,或者 Tab 进去就出不来了(键盘陷阱)。这是 P0 里最花时间的一条,但也是含金量最高的一条:键盘走不通,读屏用户、运动障碍用户、乃至只爱用键盘的高效用户全被挡在门外。

6. 每个表单控件都有标签,报错要关联

每个 input 都要有 <label>(或 aria-label),placeholder 不能代替 label——它在用户一打字就消失,读屏也不把它当标签读。报错信息要用 aria-describedby 关联到输入框,让读屏用户在聚焦输入框时直接听到错在哪。AI 生成的表单十有八九是"裸 input 加 placeholder",这一条基本每次都要返工。

7. 加一个"跳到主内容"链接

页面顶部放一个平时隐藏、Tab 聚焦时出现的"跳到主内容"链接,直达 <main>。键盘用户不用每次把导航栏 Tab 十几遍才能进入正文。实现就十几行代码,Next.js 项目里放在 layout 里一次搞定。这是成本最低、键盘用户感知最强的一处优化。

P1:想做得像样,就把这些做了

P0 保证"能用",P1 决定"好不好用"。主要是三类动态组件的 ARIA 模式,做完之后读屏用户的体验会从"能忍"变成"顺滑":

模态框:dialog 角色加焦点陷阱

弹窗打开时,焦点必须移进弹窗、Tab 被锁在弹窗里循环、Esc 能关闭、关闭后焦点回到触发按钮。AI 写的弹窗通常只管"显示和隐藏",焦点还停留在背后的页面上,读屏用户甚至不知道弹窗开了。修法见后文的代码片段,用 role="dialog" aria-modal="true" 打底,再加焦点管理。背景内容最好加上 inert 或 aria-hidden,让读屏暂时忽略它。

Tabs 和下拉菜单:用标准 ARIA 模式

Tabs 用 tablist / tab / tabpanel 角色组合,方向键切换面板;菜单用 menu / menuitem。别自己发明一套 div 加 class 的"选项卡",读屏软件认的是标准角色,不是你的 class 名。MDN 的 ARIA 实践指南里有每种模式的完整键盘交互说明,直接照抄是最稳的——标准模式的好处是读屏软件早就适配好了,你不用教用户怎么用。

Toast 和异步通知:live region

"保存成功""发送失败"这类 toast,如果只是一个突然冒出来的 div,读屏用户完全感知不到。包一层 aria-live="polite" 的 live region,内容变化时读屏会自动朗读。注意分寸:别用 alert 级别去报"保存成功"——polite 会等读完当前内容再报,assertive 会直接打断,前者适合普通通知,后者只留给真正的紧急错误。满屏 assertive 和满屏弹窗一样招人烦。

P2:加分项,顺手就做了

  • 尊重 reduced motion:用 @media (prefers-reduced-motion: reduce) 关掉自动播放、大位移动画和视差效果。前庭障碍用户会被剧烈动效诱发眩晕恶心,这不是审美问题,是生理问题。AI 爱加的入场动画、数字滚动效果,顺手包一层媒体查询就行,几行 CSS 的事。
  • 触控目标足够大:可点击区域至少 44×44px。AI 按桌面端思维排的 24px 小图标,手机用户和运动障碍用户点起来都很痛苦。用 padding 把热区撑大,视觉大小可以不变。
  • 读屏专用文本:准备一个 .sr-only 类(视觉隐藏、读屏可读),给"只看图标就懂"的按钮补文字说明,给图表补数据摘要。这是成本极低的专业度加分,几行通用 CSS 全站复用。

我的观点是:P2 不必追求一次做全,但 reduced motion 值得默认就做——它就几行 CSS,却是"你的产品是否考虑过真实人体"的试金石。

让 AI 生成无障碍代码:直接复制的 prompt 模板

关键认知先摆出来:prompt 里写"请保证无障碍"约等于没写——AI 对"无障碍"的理解通常就是加几个 aria-label 凑数。你必须写具体、可验证的规则。下面四套模板可以直接贴进你的项目 instructions 或对话里:

模板一:UI 生成的全局约束(放进项目 instructions)

生成任何 UI 代码时,必须遵守以下无障碍规则:
1. 可点击元素只用 button 或 a,禁止 div/span onClick。
2. 禁止全局 outline: none;必须保留 :focus-visible 可见焦点样式。
3. 每个 input 必须有 label 关联,placeholder 只作补充提示。
4. 所有 img 必须有 alt:信息图描述其传达的信息,装饰图用 alt=""。
5. 文字对比度:正文 ≥4.5:1,大号文字 ≥3:1。
6. 状态变化不能只用颜色表达,必须同时有文字或图标。
7. 生成后自查:列出该组件的键盘操作路径和读屏朗读顺序。

第 7 条是精髓:逼 AI 自己走一遍"键盘加读屏"推演,它常常能自己发现刚写的代码有问题。这比你事后 review 省事得多。

模板二:返工现有组件

把下面这个组件改成无障碍版本,要求:
- div onClick 改为语义化 button,保留原有样式
- 图标按钮加 aria-label
- 确保 Tab 可达、Enter/Space 可激活、焦点可见
只改无障碍相关的部分,不要重构业务逻辑。
[粘贴组件代码]

"只改无障碍相关的部分"是防 AI 顺手重构的保险栓,vibe 项目最怕修一个小问题带崩一片。约束越具体,AI 越老实。

模板三:生成表单

生成一个[注册/登录/结算]表单,要求:
- 每个字段有 label,必填项在 label 中注明"必填"并用 aria-required 标记
- 校验错误用 aria-describedby 关联到对应输入框,错误文本同时配图标
- 提交校验失败时,把焦点移到第一个出错的字段
- 整个表单可纯键盘完成

模板四:弹窗/抽屉组件

生成一个模态框组件,要求:
- role="dialog" aria-modal="true",标题用 aria-labelledby 关联
- 打开时焦点移入框内并锁住(Tab 在框内循环),Esc 关闭
- 关闭后焦点回到触发按钮
- 背景内容对读屏隐藏(inert 或 aria-hidden)
用 React 实现,给出完整代码。

用的时候注意:模板是起点,不是终点。AI 按模板生成的代码,仍然要过一遍后文 30 分钟审计流程——prompt 降低的是返工率,不是免检金牌。

30 分钟无障碍审计:免费工具一条龙

上线前留 30 分钟,按这个顺序走一遍。工具全免费,不需要买任何服务,也不需要你成为无障碍专家。

0–5 分钟:Lighthouse 跑分找方向

Chrome DevTools 里跑 Lighthouse,只勾选 Accessibility。分数不是目的,看的是它列出的具体问题:缺 alt 的图、对比度不够的文字、没有 label 的表单,一条条都是现成的修单。我的经验是:AI 生成的页面第一次跑,分数通常不好看;按修单修一轮,提到 90 分以上并不难。

5–15 分钟:axe DevTools 定点清除

装 axe DevTools 浏览器扩展(Deque 出品,免费版够用),对核心页面点一下 Scan。它比 Lighthouse 更细,能抓到"标题层级跳级""重复 id""可疑的焦点顺序"这类问题。修的原则:critical 和 serious 级别清零,moderate 看情况处理。有一点要心里有数:自动化工具只能抓到可规则化的那部分问题,这是无障碍领域的老共识,所以后 15 分钟的手动环节省不得。

15–25 分钟:拔掉鼠标,纯键盘走核心流程

这是 30 分钟里含金量最高的 10 分钟。检查点:Tab 顺序是否符合视觉顺序;所有按钮链接能否到达并激活;弹窗和菜单能否用 Esc 关闭;有没有 Tab 进去就出不来的陷阱;焦点是否永远可见。走的是你的核心路径——注册、下单、发布内容,支线页面可以先放一放。如果这 10 分钟走得顺,你的产品就已经超过了大多数 vibe 项目。

无障碍审计示意:开发者断开鼠标,仅用键盘 Tab 键遍历页面,旁边是 axe DevTools 扫描结果面板

25–30 分钟:读屏冒烟测试

Mac 按 Cmd+F5 打开 VoiceOver,Windows 装免费的 NVDA。不用学全套操作,会这几个就够:Tab 切换焦点、方向键逐行阅读、调出标题列表。目标很明确:页面标题是否被正确报出、每个按钮有没有名字、表单报错能不能听到、弹窗打开时焦点去了哪里。第一次听自己的页面被读出来,很多人会大吃一惊——这正是这 5 分钟的价值。

一句话总结这套流程:工具找"机器能发现的问题",键盘找"流程断裂",读屏找"语义灾难"。三者互补,缺一不可。

AI 代码翻车现场:before / after

下面是 AI 生成代码里最高频的 6 种无障碍翻车,每种都给修法。都是 React / Next.js 写法,直接可用:

翻车 1:div 假按钮

// ❌ Before:读屏读成死文字,键盘按不动
<div className="btn" onClick={submit}>发布</div>

// ✅ After:语义正确,键盘和读屏全通
<button type="button" className="btn" onClick={submit}>发布</button>

翻车 2:图标按钮没有名字

// ❌ Before:读屏只报"按钮",用户不知道它是干嘛的
<button onClick={close}><XIcon /></button>

// ✅ After:名字明确,图标对读屏隐藏
<button onClick={close} aria-label="关闭弹窗">
  <XIcon aria-hidden="true" />
</button>

注意图标本身加 aria-hidden="true",否则读屏会去读 SVG 里的无意义字符。

翻车 3:全局干掉焦点框

/* ❌ Before:键盘用户直接"失明" */
* { outline: none; }

/* ✅ After:鼠标点击干净,键盘 Tab 有框 */
:focus-visible {
  outline: 2px solid #2563eb;
  outline-offset: 2px;
}

翻车 4:placeholder 冒充 label

// ❌ Before:一打字提示就消失,读屏也不认
<input placeholder="邮箱地址" />

// ✅ After:label 关联加错误关联一步到位
<label htmlFor="email">邮箱地址(必填)</label>
<input id="email" placeholder="name@example.com"
  aria-required="true" aria-describedby="email-err" />
<p id="email-err"><IconWarn />请输入有效的邮箱地址</p>

翻车 5:弹窗不管理焦点

// ❌ Before:弹窗开了,Tab 还在背后页面乱飞
{open && <div className="modal">...</div>}

// ✅ After:最小可用的焦点管理
const prevFocus = useRef(null);
useEffect(() => {
  if (!open) return;
  prevFocus.current = document.activeElement; // 记住触发点
  dialogRef.current?.focus();                  // 焦点移入
  const onKey = (e) => e.key === 'Escape' && onClose();
  document.addEventListener('keydown', onKey);
  return () => {
    document.removeEventListener('keydown', onKey);
    prevFocus.current?.focus();                // 焦点回去
  };
}, [open]);

<div ref={dialogRef} tabIndex={-1} role="dialog"
  aria-modal="true" aria-labelledby="dlg-title">...</div>

生产环境我的建议是:直接用 Radix UI、Headless UI 这类已经处理好焦点陷阱的组件库,别自己手写 trap——焦点陷阱的细节比你想象的多。vibe 项目时间紧,用无障碍做好的组件库是最划算的选择。

翻车 6:toast 读屏听不到

// ❌ Before:突然冒出来的 div,读屏用户直接错过
{msg && <div className="toast">{msg}</div>}

// ✅ After:包一层 live region,变化自动朗读
<div aria-live="polite" role="status" className="toast-wrap">
  {msg && <div className="toast">{msg}</div>}
</div>
焦点可见状态对比示意:左侧按钮带蓝色 :focus-visible 焦点框,右侧焦点框被全局 outline:none 干掉后键盘用户无法定位

上线前验收清单:逐条打勾

把下面这张表贴进你的发布 checklist,和"跑通测试"放在同一行。上线前逐条打勾,一条不勾不发布:

检查项怎么验
全站无 div/span 假按钮全局搜索 onClick,挂在 div/span 上的逐个换掉
焦点框永远可见纯 Tab 走一遍,焦点位置任何时候都看得见
图片 alt 完整axe 扫描无缺失;装饰图 alt=""
文字对比度达标关键文字 4.5:1,大号文字 3:1,抽查通过
核心流程纯键盘走通拔掉鼠标,走完注册/下单/发布主路径
无键盘陷阱Tab 能进能出,弹窗 Esc 可关
表单 label 全覆盖每个 input 有 label;报错能被读屏听到
跳到主内容链接首屏按一下 Tab 就能跳过导航
弹窗焦点管理打开移入、Tab 锁住、Esc 关闭、关闭返回,四项全对
Toast 可被读屏听到aria-live 包裹,VoiceOver/NVDA 能报出通知
动效可关闭prefers-reduced-motion 下无自动播放和大位移动画
读屏冒烟通过听一遍核心页,没有一连串无名"按钮"

结语:无障碍是产品完成度的试金石

说点判断。很多人把无障碍当成"爱心加分项",排期永远在"有空再做"里。但换个角度想:一个连键盘都走不通的产品,它的完成度真的及格吗?你用 AI 一天搭出的 demo,能打动朋友;但只有把上面这份清单清零的产品,才敢说自己"做好了"。

还有一个很少被提到的好处:无障碍优化和 SEO、自动化测试是同一批受益者。语义化 HTML 让搜索引擎更懂你的页面,键盘可操作让 E2E 测试更好写,live region 会逼你的状态管理更清晰。你为残障用户做的每一分工作,都会以另一种形式回到产品质量上。

AI 时代做产品的门槛被打到了地板,但"能跑起来"和"所有人都能用"之间,差的正是这份清单。把它塞进你的发布流程,和跑测试、看报错一样自然——下次上线前,花 30 分钟走一遍,你的产品就超过了市面上大多数 vibe 项目。这不是情怀,是专业度。

浏览项目广场发布你的项目

相关文章

帮助中心知识库概念插画:搜索框、分类卡片与文档页面构成的自助支持体系示意
指南
用户帮助中心:vibe 项目的知识库与自助文档落地实战

UX 再好也挡不住用户想确认政策、搜报错信息、付款前做信任检查。这篇指南给一人开发者一套可落地的帮助中心方法论:四象限决策矩阵决定写什么、6 个顶层分类模板、6 种文章类型的写作骨架、用 AI 从代码库起草文档的三段式工作流、一人份 docs-as-code 最小搭建、绑进发版的 doc-debt 清单,以及每月 1 小时的维护 SOP。

独立开发产品策略设计体验
Playwright E2E 回归测试流程示意图:一位独立开发者正在查看浏览器测试报告,背景是 CI 流水线
指南
AI 时代的一人回归测试:Playwright E2E 最小成本方案

AI 改代码最怕改 A 坏 B。本篇是《AI 测试策略》的执行层续篇:用 Playwright 加 5 条黄金路径、data-testid 约定与 GitHub Actions,一小时搭起一人团队的 E2E 回归护城河,每周只花 1 小时维护,免费额度内跑完,并附可直接复制的配置、测试与 CI 代码。

测试与质量开发工作流AI 编程实践
AI Agent 的工具调用轨迹正在对照黄金测试集接受检查,分层通过率展示与 CI 门禁拦下一次合并请求
指南
别凭感觉迭代:给你的 AI Agent 搭一套评估基准

模型、提示词、工具三者任一变化,都可能在你庆祝修好的同时悄悄破坏 Agent 的能力。本指南从零讲透评估基准搭建:从真实流量挑 20 个 case 组成黄金测试集,代码评分器加校准过的 LLM 裁判,三层分开记分,防自欺清单,CI 门禁真正拦下合并,再用线上采样与影子运行形成闭环。

测试与质量软件测试AI 智能体