扫描当前目录或指定文件中 React/TSX 组件缺失的无障碍(a11y)标注,并自动修复。
检测:可点击元素中仅包含图标组件(如 <YbIcon>、 <Icon>、 <SvgIcon>、 <img>),没有可见文本,也没有 aria-label / aria-labelledby。
修复:根据图标的 type / name 属性或上下文推断标签内容,添加 aria-label。如果项目使用 i18n 函数( t()),用其包裹标签文本。
检测: <div> 或 <span> 带有 onClick 处理器但缺少:
role="button"tabIndex={0}onKeyDown / onKeyPress 键盘事件处理(Enter/Space 触发点击)修复:添加 role="button"、 tabIndex={0},以及一个在 Enter/Space 时触发点击的 onKeyDown 处理器。
检测: <img> 元素中:
alt 属性完全缺失alt 为无意义值,如 alt="image"、 alt="photo"、 alt="picture"、 alt="icon"装饰性图片使用 alt="" 是 合法的,不应标记。
修复:根据上下文(文件名、周围文本、父组件语义)添加描述性 alt。如确为装饰性图片,添加 alt="" 和 role="presentation"。
检测: <input>、 <textarea>、 <select> 没有关联的 <label>(通过 htmlFor / 包裹方式)或 aria-label / aria-labelledby。
修复:根据 placeholder、附近标题或父级上下文推断文本,添加 aria-label。可行时优先使用显式的 <label> 包裹。
检测:弹窗/对话框组件(如 Dialog、 Modal、 YbcDialog、 Drawer)缺少:
aria-modal="true"(如果底层库未设置)aria-labelledby 或 aria-label 指向对话框标题修复:添加指向标题元素 id 的 aria-labelledby,或在无标题元素时添加 aria-label。焦点管理问题以警告形式标注。
检测:动态内容区域(Toast 通知、加载状态、错误提示、聊天消息)缺少 aria-live、 aria-atomic 或 role="status" / role="alert"。
修复:添加合适的 aria-live="polite"(默认)或 aria-live="assertive"(错误/警告),以及需要整体重新播报时添加 aria-atomic="true"。
text
任务进度:
- [ ] 步骤 1:确定扫描范围(文件/目录)
- [ ] 步骤 2:按 7 条规则搜索违规项(含兼容性)
- [ ] 步骤 3:汇总审查报告
- [ ] 步骤 4:应用自动修复
- [ ] 步骤 5:验证修复未引入新问题
使用 Glob 查找目标目录下所有 .tsx 文件:
text
**/*.tsx
排除 node_modules、 dist、 build、 .next、 __tests__、 *.test.tsx、 *.spec.tsx。
针对每条规则,使用 Grep 查找潜在违规项:
纯图标按钮:
text
onClick.*<(YbIcon|Icon|SvgIcon)
然后验证父级可点击元素是否存在 aria-label。
div 模拟按钮:
text
<(div|span)[\s\S]*?onClick
然后验证是否存在 role="button" 和 tabIndex。
缺失 alt:
text
<img[\s\S]*?(?!alt=)
未标注的表单元素:
text
<(input|textarea|select)[\s\S]*?(?!aria-label)
未标注的弹窗:
text
<(Dialog|Modal|YbcDialog|Drawer)
然后验证是否存在 aria-labelledby 或 aria-label。
缺少实时区域标注的动态内容:
text
(toast|Toast|notification|Notification|loading|Loading|errorMsg|errorMessage)
然后验证附近是否存在 aria-live 或 role="alert" / role="status"。
兼容性问题:
text
inert[^a-zA-Z]
检查是否有 inert 回退。
text
:focus-visible
检查是否有 :focus 基础样式回退。
text
suppressHydrationWarning
检查同一元素是否有正确的 alt / aria-label。
text
role="(status|alert|feed)"
在微信/QQ 环境中这些 role 不可靠,检查是否有语义化元素替代或多通道回退。
按以下格式输出审查结果:
text
## 无障碍审查报告
### 文件:src/components/Example.tsx
| 行号 | 规则 | 问题 | 建议修复 |
|------|------|------|----------|
| 42 | icon-button-a11y | onClick div 中的 `<YbIcon>` 缺少 aria-label | 添加 `aria-label={t('关闭')}` |
| 78 | div-button-a11y | `<div onClick>` 缺少 role 和键盘交互 | 添加 `role="button"` tabIndex={0} onKeyDown |
使用 StrReplace 逐项应用修复。保留:
t() / useTranslation,用其包裹标签文本修复后,对修改过的文件运行 ReadLints,检查是否引入了新错误。
TDesign 的 Button、 Dialog、 Input 等通常内部处理了基本无障碍。重点关注:
content 或 children 等提供隐式标签的 propsYBButton、 YbcDialog 是薄层封装。检查 a11y props 是否被正确透传。如果封装层吞掉了 aria-* props,需要标记。
<Image>#Next.js 的 Image 组件默认要求 alt 并会发出警告。仍需验证 alt 文本是否有实际意义。
本项目运行在多种平台上,不同引擎对无障碍 API 的支持存在差异,修复时必须考虑兼容性。
平台引擎无障碍支持等级桌面端(Tauri macOS)WKWebView较好,VoiceOver 支持完整桌面端(Tauri Windows)WebView2 (Chromium)好,NVDA/JAWS 支持完整桌面端(Tauri Linux)WebKitGTK一般,Orca 支持有限Chrome/Edge 扩展Chromium好微信内置浏览器自研 X5 / 系统 WebView较差,部分 ARIA 属性被忽略QQ 内置浏览器MQQBrowser 内核较差PC 微信Chromium 内嵌一般企业微信系统 WebView一般小程序 WebView受限沙箱差,焦点管理受限
7a. inert 属性兼容(compat-inert)
inert 属性在旧版 WebView 中不被支持。如果使用了 inert,需要同时提供 polyfill 或回退方案( aria-hidden="true" + tabIndex={-1})。
7b. <dialog> 元素兼容(compat-dialog)
原生 <dialog> 元素在 X5 内核、旧版 WKWebView、小程序 WebView 中可能不受支持。优先使用库组件(TDesign Dialog / YbcDialog)而非原生 <dialog>。
7c. focus-visible 伪类兼容(compat-focus-visible)
:focus-visible 在微信 X5 内核中可能不生效。需要同时保留 :focus 样式作为回退:
css
.btn:focus { outline: 2px solid var(--focus-color); }
.btn:focus:not(:focus-visible) { outline: none; }
.btn:focus-visible { outline: 2px solid var(--focus-color); }
7d. aria-live 在受限 WebView 中的兼容(compat-live-region)
微信/QQ 内置浏览器中 aria-live 可能不触发屏幕阅读器播报。对于关键通知,除了 ARIA 标注外,建议同时提供视觉反馈(如 Toast 动画)和触觉反馈(如震动 API)作为多通道回退。
7e. 焦点管理在小程序 WebView 中的限制(compat-focus-trap)
小程序 WebView 沙箱中 document.activeElement 和程序化 focus() 行为不一致。弹窗焦点捕获应通过库组件实现,避免直接操作 DOM focus。检查是否存在 isMpWebview 条件分支来处理此类差异。
7f. role 属性在 X5 内核中的支持(compat-role)
微信 X5 内核对某些 ARIA role(如 role="status"、 role="alert"、 role="feed")支持不完整。在这些环境中,优先使用语义化 HTML 元素( <button> 替代 role="button"、 <nav> 替代 role="navigation")。
7g. suppressHydrationWarning 与无障碍的交叉(compat-hydration)
项目中大量使用 suppressHydrationWarning。检查设置了此属性的 <img> 元素是否同时有正确的 alt,防止 SSR/CSR 不一致导致 alt 文本丢失。
<button>、 <a>、 <input> 在所有引擎中的无障碍支持都优于 ARIA 标注的 <div>isDesktop、 isMpWebview、 isWeChat 等环境检测,为受限平台提供替代方案if ('inert' in HTMLElement.prototype))而非 UA 嗅探当存在大量违规时,按以下顺序修复(影响从高到低):