---
url: /zh/guide/typescript/view-engine-accessibility.md
description: wow-view-engine 对 WCAG 2.2 AA 的符合性声明——评估方法、纯键盘与读屏走查的结果、这次修掉的问题、逐条准则的支持程度与已知缺口。
---

# 视图引擎的可访问性

::: info 随 Wow 9.2.0 发布
`@ahoo-wang/wow-view-engine` 随 Wow 9.2.0 发布，在此之前不在 npm 上；兼容规则见[视图引擎](./view-engine.md)页。本页描述的是仓库里当前的状态，随代码一起更新。
:::

本页是视图引擎界面（`@ahoo-wang/wow-view-engine/ui`：记录工作台、分析工作台、仪表盘、两种嵌入）对 [WCAG 2.2](https://www.w3.org/TR/WCAG22/) A 级与 AA 级的符合性声明。结论先说：

| 支持 | 部分支持 | 不支持 | 不适用 |
|---:|---:|---:|---:|
| 41 | 0 | 0 | 14 |

声明最初列为「部分支持」的五条——2.4.11 焦点不被遮挡、2.5.7 拖动、2.5.8 目标尺寸、3.1.2 局部语言与 4.1.3 状态消息——在[之后修掉的已知项](#之后修掉的已知项)之后都是「支持」。2026-09-30 的第二轮走查覆盖了 09-25 之后加的交互，[修掉了其中一批](#第二轮走查修掉的问题)；当时留在「部分支持」的五条——1.3.1、2.4.3、3.1.2、3.3.2、4.1.3，原因都在**声明式操作**（行主操作、⋯ 菜单、批量与操作表单）——在[它们的修复](#声明式操作的修复)（PR #3834）之后都是「支持」。没有任何一条是「不支持」，但这份声明**不是**第三方审计，也**没有**用真实的读屏软件走过——见[评估方法](#评估方法)里的局限与[已知缺口](#已知缺口)。

## 声明的范围

* **评估对象**：Wow 仓库 `main`（`c1494d2ed`）加上随本页这一版合入的修复（第二轮走查，PR #3826；声明式操作的修复，PR #3834），`typescript/wow-view-engine` 的 `/ui` 入口；第一轮评估的是 `b17f36a3c`。无头的根入口与 `/react` 不画界面，不在范围内。
* **宿主的责任**：视图引擎总是放在宿主的页面里。页面标题（2.4.2）、页面语言（3.1.1）、跳到主要内容的链接、全站导航的一致性、登录（3.3.8）与帮助入口（3.2.6）都是宿主的；覆盖 `--fve-*` 颜色变量的宿主要自己守对比度（见[视图引擎的主题](./view-engine-theming.md#对比度由覆盖的人负责)）。下表里「不适用」的几条多半是这个原因。
* **示例数据**：走查在 [Storybook](/storybook/) 的宿主外壳里进行，用的是仓库自带的零售数据集与回归夹具。

## 评估方法

* **日期**：第一轮 2026-09-25；第二轮 2026-09-30（09-25 之后加的声明式操作、`ViewHost`、分析托盘的展开与撤销提示、看板的提示 toast、图型选择的两列网格，以及强制颜色与降低动效），修复后在本分支上重走了一遍。
* **环境**：macOS 27.0；Storybook 10.6 开发服务器；Playwright 1.63 驱动的 **Chromium 153** 与 **WebKit 26.6**（Safari 的引擎），视口 1440×900，另在 320 与 900 像素宽下复查。第二轮只用 Chromium，跑在静态构建的 Storybook 上，视口 1440×900 起，另测 1280×720、640×450（约 200% 缩放）与 320×640。
* **纯键盘走查**：每一步都是一次真实的按键（Tab、Shift+Tab、方向键、Enter、空格、Esc、Alt／Shift 组合），不用鼠标、不用脚本点击。每按一下记录焦点落在哪个元素（角色与名字）、焦点环是否画出、元素是否在视口内、正中那一点是否被别的元素盖住（2.4.11），以及播报区（`aria-live`、`role=status|alert`）新说了什么。
* **读屏一半**：**没有驱动 VoiceOver**。打开 VoiceOver 的 AppleScript 控制要改系统的安全设置，这次不做；改用三样东西：

  1. Chromium 自己算出的无障碍树（CDP `Accessibility.getFullAXTree`）——这是浏览器交给平台读屏接口的名字、角色与状态；
  2. Playwright 的 ARIA 快照，看结构、地标、对话框与表格；
  3. 每一次按键后播报区的文字变化。

  它们能说明「念出来的应该是什么」，说明不了读屏软件实际怎么念、念几遍、会不会被别的播报打断。真人用 VoiceOver 与 NVDA 走一遍是一条待办。
* **自动检查**：每个 Storybook 故事在交互之后跑 axe（`@storybook/addon-a11y`，`test: 'error'`，有违规即失败），jsdom 单元测试里另有 axe 断言；内置主题的对比度由对比度矩阵测试守着。第二轮另把 axe 4.13 跑在 11 个故事 × 4 套预设 × 亮暗上，88 次全无违规。
* **强制颜色与降低动效**：第二轮用 Playwright 的 `forcedColors: 'active'` 走了一遍菜单、选中行、当前视图与焦点（Windows 高对比主题的近似），用 `reducedMotion: 'reduce'` 看动画是否压住；另注入 WCAG 1.4.12 的文字间距。
* **WebKit 的一点差别**：Safari 默认的 Tab 只停在文本框与带 `tabindex` 的控件上（「按 Tab 键高亮显示网页上的每个项目」关着）。Playwright 的 WebKit 照这个默认走，所以 WebKit 那一列里链接和部分按钮不在 Tab 顺序里是平台行为，不算缺陷；Option+Tab 仍能到。

## 走查结果

「键盘」一列：能否只用键盘完成、焦点顺序、焦点是否看得见、有无焦点陷阱、捷径与快捷键是否找得到。「读屏」一列：名字、角色、状态、播报与结构。✅ 能完成，⚠️ 能完成但有已记录的差距，🔧 走查时发现或列为已知缺口、已经修掉（随本页，或[之后](#之后修掉的已知项)）。

### 记录工作台

| 任务 | 键盘 | 读屏 |
|---|---|---|
| 打开一个视图 | ✅ 侧栏列表每个视图一个 Tab 站，Enter 打开，焦点留在列表上 | ✅ 「正在打开视图」「共 N 条记录」 |
| 筛选 | 🔧 「添加」→ 字段搜索框 → 勾选 → Esc 落到新条件的值框，直接填值。**「放弃筛选修改」「清空」按下后焦点掉到页面开头**，已修：落到「应用」 | ✅ 条件的每个控件以字段名命名（「仓库 值」「仓库 条件取反」）；应用后「正在查询」「共 N 条记录」 |
| 排序 | ✅ 整行表头一个 Tab 站，←／→ 在列间走，Enter 排序，Shift+Enter 追加 | 🔧 表头 `aria-sort`，按钮名字说按下去会怎样（「按订单号降序排序」）。**列名是按钮的动作加列宽把手的名字**（「按订单号升序排序 调整 订单号 宽度」），在格子间移动时整串被当列名念，已修：表头以列名命名 |
| 调列宽 | 🔧 表头上 Alt+←／→（Shift 大步），Alt+Enter 恢复自适应；**只写在 `aria-keyshortcuts` 里，看不见**，已修：列设置里写出这几个键，每行还有一个宽度框 | 🔧 **每一步都重跑查询并念「正在查询」「共 N 条记录」，新的宽度一次也不念**，已修：调宽度不查询，每一步说「〈列〉宽 N 像素」 |
| 翻页 | 🔧 下一页、上一页、跳页框都可达；**翻到最后一页（或回到第一页）时按下的那一步变灰，焦点掉到页面开头**，已修：落到另一步 | ✅ 分页是有名字的 `navigation`；翻页后念总数 |
| 列设置 | 🔧 搜索框 → 每行的把手、复选框、汇总、宽度、固定；**「显示 〈列〉」复选框根本 Tab 不到**（工具栏的漫游焦点上下文漏进弹层），已修，并从根上修掉：弹层画在工具栏外面；Esc 要按两下（第一下先收起键盘焦点打开的提示框） | ✅ 行的顺序移动「仓库 已移到第 3 位，共 4 位」，固定「状态 已固定到左侧」 |
| 导出 | ✅ 模态对话框，焦点困在框内，Esc 或「取消」回到「导出」 | ✅ 对话框有名字，内容读出条数、条件、列与文件名 |
| 另存为 | ✅ 「更多视图操作」菜单 → 对话框；创建后焦点落到新视图的名字上 | ✅ 「正在打开视图」 |

### 分析

| 任务 | 键盘 | 读屏 |
|---|---|---|
| 在托盘里搭问题 | 🔧 「分析」展开托盘，焦点进托盘；添加维度、指标都是菜单。**加上最后一个可分组字段后「添加维度」变灰，焦点掉到页面开头**，已修：落到新长出的维度卡上 | ✅ 托盘分「范围、维度、指标、结果」四个有名字的区域；每改一下「正在查询」「N 组」 |
| 展开与撤销提示 | 🔧 「展开 商品」按下去带走了订单级的指标，托盘底部出一句提示与「撤销」「关闭提示」。**「展开 商品」被元素卡顶替、「撤销」「关闭提示」随提示消失，焦点都掉到页面开头**，已修：展开后落到新的元素卡，撤销后回到「展开 商品」，关闭提示后落到元素卡 | ✅ 「展开 商品 后去掉了 2 个指标：本月至今 GMV、上月同期 GMV」；撤销后「已撤销，问题恢复原样」 |
| 换图型 | 🔧 「可视化」进面板，焦点先到面板标题，Tab 进图型组（radiogroup：一个 Tab 站，方向键选）。**结果工具栏的方向键跳过「可视化」**（它是工具栏里第二个 Tab 站），已修 | ✅ 图型是 `radio`，灰掉的写明原因（「热力图 要两个维度」） |
| 框选一段 | 🔧 表格布局里行是一个 Tab 站，↑／↓ 走，Enter 是这一组，Shift+Enter 是两行之间这一段。**Shift 的用法只在行的描述里**，已修：一行按出的追问菜单在所选的组下面写出这句。图上的标记只有指针够得着（ECharts 没有键盘导航），表格布局就是键盘的路 | ✅ 「已选中 创建时间 介于 … ，追问菜单已打开。」；行的描述说了 Shift 的用法 |
| 追问 | 🔧 追问菜单方向键选、Enter 执行。**「查看这些记录」换掉整个视图，焦点掉到页面开头；来源条的「返回」同样**，已修：两者都落到新视图的名字上 | ✅ 菜单以所选的组命名 |
| 导出图片 | ✅ 「导出」菜单里 PNG／SVG，Enter 下载，焦点回到「导出」 | ✅ 下载由浏览器宣布 |
| 读图 | —— | ✅ 图是有名字的 `role=img`，`aria-describedby` 一句摘要（「共 30 期，从 … 到 …，总体上升；最高 …，最低 …」），旁边一张带 `caption` 的只给读屏的数据表；🔧 **指标卡的走势小图没有摘要句**，已修：它有时间轴那一句，读屏表首列以维度命名 |

### 仪表盘

| 任务 | 键盘 | 读屏 |
|---|---|---|
| 进入搭建 | ✅ 「编辑」→ 焦点落到编辑条的「正在编辑」；「保存」后回到「编辑」 | ✅ 编辑条是有名字的区域；「仪表盘已保存」 |
| 添加面板 | ✅ 「添加」菜单 → 对话框（搜索框、按种类筛、分组列表），Esc 回到「添加」 | ✅ 分组「系统视图／共享视图／我的视图」，已在板上的标明 |
| 移动、缩放面板 | ✅ 抓手上 Enter 拿起，方向键移动，Shift+方向键缩放，Enter 放下，Esc 放回；指针拖动的键盘等价物完整。🔧 **拖不了的指针没有路**，已修：面板「⋯」里「移动或调整大小」，一次点击一步 | ✅ 「正在摆放…」「现在在第 2 列第 3 行，宽 14 列、高 4 行」「就放在这里」「回到了原处」 |
| 筛选 | ✅ 筛选条的每个控件可达，「清空」后焦点落到第一个值上 | 🔧 **改了值之后板子什么也不说，面板失败也不播报**，已修：面板落定后说「已按〈筛选〉筛选，N 个面板已更新。」，有失败时接上「M 个面板没能加载。」 |
| 自动接线的提示 | ✅ 加时间筛选后「已自动接上…」toast 里的「只接刚选的面板」与「关闭」都可 Tab 到 | ✅ toast 在名为「接线提示」的礼貌型区域里念出 |
| 交叉筛选 | ✅ 图表面板的标记只有指针够得着；键盘的等价物是筛选条上同一个筛选；表格布局的面板行可按。面板头上的「点击筛选「仓库」」是一颗说明用的按钮，聚焦显示说明、按下无动作 | ✅ 说明作为描述念出 |

### 声明式操作

宿主用 `actions()` 声明的命令：行上的主操作与「⋯」菜单、多选后的批量栏、带表单的操作与危险确认、进度与结果。第二轮走查时加的，发现的缺口已[修掉](#声明式操作的修复)，下表按修复后的分支重走（Storybook 里 Chromium 上的纯键盘，与 jsdom）。

| 任务 | 键盘 | 读屏 |
|---|---|---|
| 运行一个操作 | 🔧 行主操作与「⋯」菜单都可达，Enter 执行。**运行时同一面上的操作按钮全变灰，焦点掉到页面开头**，已修：忙着的按钮仍可获焦（`aria-disabled`），「⋯」照样能开、菜单项停用，问题框关上回到发问的按钮；刷新带走那一行或多选条时，焦点落到结果行的「知道了」 | 🔧 「发货 · 正在执行 0/1」，然后「发货 · SO-1003 已完成；共 4 条记录」。**用 props 传措辞的宿主念成英文，结果句 10ms 后被「共 N 条记录」盖掉**，已修：面的措辞传下去，结果句与刷新的条数合成一句 |
| 灰掉的操作 | 🔧 **原生 `disabled`，Tab 不到**，已修：可获焦，获焦即开提示 | 🔧 理由是按钮的描述 |
| 带表单的操作 | ✅ 对话框困住焦点，Esc 回到「⋯」；🔧 提交按钮始终可按，必填项空着时按下会标出该项并把焦点送过去 | 🔧 **「必填」没有对辅助技术暴露、表单用的是 `alertdialog`**，已修：标签指向控件，`aria-required`，「必填」是它的描述，提交后才 `aria-invalid`；带表单的与例行的问题是 `dialog`，只有不用填的危险确认是 `alertdialog` |
| 多选与批量 | 🔧 **批量按钮各是一个 Tab 站**，已修：它们是结果工具栏的项，整条一个 Tab 站、方向键穿过 | ✅ 「已选 N 条」；按下前「发货 3/4 条」说出几条能做 |

### 嵌入

| 任务 | 键盘 | 读屏 |
|---|---|---|
| 静态嵌入（视图、仪表盘） | ✅ 只有读的控件：表头、复制、面板正文（可滚动区域是 Tab 站） | ✅ 两个嵌入的地标按各自的视图命名（「正在显示：待出库订单」），不重名；嵌入里没有 `main`，由宿主给 |
| 交互嵌入 | ✅ 「在工作台中打开」、导出、铺满屏幕（Esc 收起）、搜索、排序、分页；锁定的筛选读作它的值 | ✅ 与工作台同一套名字与播报 |

### 横向的几条

* **焦点可见**：控件只有一种画法（1px `--ring` 加 3px 光晕，预设可加宽），行与卡片另画在格内；菜单、选择框与组合框里键盘所在的那一项在边内画 2px `--ring`。都对相邻底 ≥3:1（有测试守着）。🔧 第二轮发现菜单项的位置只靠一层高亮填色，neutral 与 azure 下对弹层底 1.03～1.07:1，面板、下钻、导出菜单的项在 contrast 下也只拿到约 1.2:1 的浅灰，已修：加那道 `ring`，高亮规则按角色选项。走查中所有控件都画出了焦点。
* **强制颜色**：🔧 菜单里每一项都画着同一圈框、分不出获焦的那一项，弹层没有边，已修：键盘所在的项画 `Highlight` 的框，其余不画，弹层画 `CanvasText` 的边。焦点、选中行、当前视图与按下的开关都看得见。
* **降低动效**：`prefers-reduced-motion` 下动画与过渡压到 0.01ms，进度圈与骨架保留；图表另读这项设置。
* **焦点被遮挡**：🔧 仪表盘面板里明细表最底下几行的「复制」聚焦时整颗落在粘性的「全部」行底下，已修（`scroll-padding`）。🔧 列宽比内容窄时，溢出的单元格盖住右边一格里聚焦的按钮大半，已修：有宽度的格子裁掉溢出，复制按钮整颗留在自己格里。
* **焦点陷阱**：没有。模态对话框按设计困住焦点，Esc 关闭并还给打开它的控件；弹层与菜单 Tab 出去即关闭。
* **跳过重复内容**：视图引擎给出有名字的地标（`main` 以视图名命名、视图列表是 `navigation`、筛选、编辑条与已应用条是 `region`）和两级标题；宿主页面自己已有 `main` 时，工作台传 `landmark="region"`，主列改成同名的 `region`，页面上只有一个 `main`（Q64，2026-09-25 已定）；工具栏、表头、结果行各是一个 Tab 站。每行的勾选框与「复制」各占一个 Tab 站，长列表要按很多下——用标题与地标跳读更快。跳到主要内容的链接是宿主的。
* **快捷键的可发现性**：抓手、行与列设置的把手都在名字或描述里说了键；Alt+←／→ 调列宽写在列设置里，Shift 选一段写在一行按出的追问菜单里。没有单字符快捷键。
* **语言**：视图的面把措辞目录的语言写成 `lang`（它打开的每个弹层也是），英文页面里的中文措辞按中文念。🔧 三处第三方部件自己写的英文漏在中文面上——数字框的角色说明「Number field」、日历月份切换的「Navigation bar」、值建议加载时的「Loading」——已修：前两处按措辞目录说（「数字输入框」「月份切换」），第三处进度圈不再单独念，旁边的字已说了。声明式操作在用 props 传措辞的宿主上仍念英文（见上）。

## 本次修掉的问题

都随同一个 PR 合入，各有回归测试（jsdom 单元测试或 Storybook 交互测试）：

| 问题 | 修法 | 测试 |
|---|---|---|
| 筛选的「放弃筛选修改」「清空」按下后焦点掉到 `body` | 落到「应用」 | `test/filterPanel.test.tsx` |
| 翻到头时按下的那一步变灰，焦点掉到 `body` | 页面落定后落到另一步 | `test/recordPagination.test.tsx` |
| 加上最后一个可分组字段后「添加维度」变灰，焦点掉到 `body` | 菜单把焦点交给新长出的维度卡 | `test/analysisFocus.test.tsx` |
| 追问「查看这些记录」、来源条「返回」换掉视图，焦点掉到 `body` | 一个视图顶替另一个、焦点又掉了时，落到新视图的名字上 | 故事 `KeyboardFollowUpKeepsTheKeyboard` |
| 结果工具栏的方向键跳过「可视化」 | 「可视化」进工具栏的漫游顺序 | `test/analysisFocus.test.tsx` |
| 列设置、卡片设置的复选框 Tab 不到 | 起初明写 `tabIndex`；之后根因已修（见下） | `test/resultToolbar.test.tsx`、`test/cardSettings.test.tsx` |
| 焦点落在粘性表尾底下（2.4.11） | 表格的滚动口带 `scroll-padding-block` | 故事 `FocusClearsTheStickyBands` |

## 之后修掉的已知项

本页起初列为缺口的已知项，在之后的一个 PR 里修掉，各有回归测试：

| 问题 | 修法 | 测试 |
|---|---|---|
| 工具栏的漫游焦点漏进弹层：Safari 默认设置下固定钮与汇总下拉被 Tab 跳过，复选框靠明写 `tabIndex` 止血 | 列设置、卡片设置与排序的弹层画在工具栏外面，以 `Popover.createHandle` 连着工具栏里的按钮；记录与分析结果工具栏打开的导出窗口同样画在外面（`Dialog.createHandle`）；明写的 `tabIndex` 删掉，每个控件自己写着 `tabindex="0"` | `test/resultToolbar.test.tsx`、`test/chartImageExport.test.tsx`；故事 `ToolbarPopupsKeepTheirTabStops` |
| 面板的移动与缩放、列宽只能拖（2.5.7） | 面板「⋯」里「移动或调整大小」（左移、右移、上移、下移、加宽、变窄、加高、变矮），一次点击一步；列设置每行一个宽度框 | `test/dashboardPlacement.test.tsx`、`test/columnWidthInput.test.tsx`；故事 `PanelArrangedByClicks`、`ColumnWidthByTyping` |
| 列宽拖动区只有 8px（2.5.8） | 宽度框就是间距例外允许的等价控件；细条不压住排序按钮 | 同上 |
| 列宽、列序、固定、汇总都重跑查询并跟着念（4.1.3） | 只改画法的编辑不查询，汇总变了只发聚合；每一步说新宽度 | `test/restyle.test.tsx`、`test/headerRoving.test.tsx`；故事 `WidthStepsSayTheWidth` |
| 仪表盘改筛选与面板失败不出声（4.1.3） | 面板落定后说一次：哪些筛选、几个面板、几个失败 | `test/dashboardFilterOutcome.test.tsx`；故事 `FilterChangeIsSaid` |
| 记录表没有名字；小图没有摘要句，读屏表首列表头是「类别」 | 记录表以视图名或面板名命名；小图有时间轴那一句，首列用维度的显示名 | `test/tableNames.test.tsx`；故事 `TableNamedByItsView` |
| 溢出的单元格盖住聚焦的复制按钮（2.4.11） | 裁切格子的类丢了前缀、什么也没做；补上，可复制的一格让字截断 | 故事 `CopyStaysInANarrowCell` |
| 视图的面不声明语言（3.1.2） | 面与弹层按措辞目录写 `lang`，宿主可覆盖 | `test/surfaceLanguage.test.tsx` |
| Alt+←／→、Shift+Enter 只在读屏的描述里 | 写在列设置与追问菜单里 | `test/columnWidthInput.test.tsx`；故事 `KeyboardPicksAStretch` |

## 第二轮走查修掉的问题

随 PR #3826 合入，各有回归测试：

| 问题 | 修法 | 测试 |
|---|---|---|
| 「展开 商品」按下后焦点掉到 `body`（2.4.3） | 展开到链的最后一层时落到新的元素卡 | `test/elementsSlot.test.tsx`；故事 `ExpansionUndo` |
| 撤销提示的「撤销」「关闭提示」按下后焦点掉到 `body`（2.4.3） | 按下时就算好落点：撤销回到「展开 商品」，关闭落到元素卡 | 同上 |
| 菜单项的位置只靠高亮填色，neutral、azure 下对弹层底 1.03～1.07:1（1.4.11、2.4.7） | 键盘所在的项在边内画 2px `--ring`，对比度矩阵量它对弹层底 ≥3:1 | `test/presetContrast.test.ts`；故事 `MenuFocusMark*` |
| 面板、下钻、导出菜单的项拿不到主题的高亮色（contrast 下约 1.2:1） | 高亮规则按 `menuitem`／`option` 角色选，不按 `data-slot` 名单 | 故事 `PanelMenuHighlight` |
| 强制颜色下菜单分不出获焦项、弹层无边（2.4.7） | 获焦项画 `Highlight` 的框，其余不画，弹层画 `CanvasText` 的边 | 故事 `MenuInForcedColors` |
| 数字框念英文「Number field」，日历的「Navigation bar」，建议列表的「Loading」（3.1.2） | 按措辞目录说；进度圈不重复念 | `test/surfaceLanguage.test.tsx`、`test/suggestedValue.test.tsx` |
| 表头的名字是排序按钮的动作加列宽把手的名字（1.3.1、2.4.6） | 表头以列名命名，排序状态由 `aria-sort` 给 | `test/tableNames.test.tsx` |

### 声明式操作的修复

随 PR #3834 合入，各有回归测试：

| 问题 | 修法 | 测试 |
|---|---|---|
| 运行一个操作后焦点掉到页面开头——行主操作、「⋯」菜单、批量栏（2.4.3） | 忙着与不可用的按钮 `focusableWhenDisabled`（`aria-disabled`，按下被吞）；「⋯」照样能开；问题框关上回到发问的控件；刷新带走那一行或多选条时，掉下的焦点落到结果行的「知道了」 | `test/declaredActions.test.tsx`「the keyboard after a command」；故事 `RowPrimaryAndOverflow`、`BulkPartialAvailability`、`FormInput`、`DangerConfirm`（Chromium 上断言焦点与读屏区） |
| 灰掉的行主操作 Tab 不到，理由只在悬停提示与「⋯」菜单的组名里 | 可获焦，获焦即开提示，理由是它的描述 | 同上 |
| 用 props 传措辞的宿主上，操作的开始与结果念英文（3.1.2），结果句随即被「共 N 条记录」盖掉（4.1.3） | 记录视图把措辞传给操作面；结果句领着刷新的条数合成一句 | `test/declaredActions.test.tsx`「what the surface says」；故事 `RowPrimaryAndOverflow`、`BulkPartialAvailability`、`FormInput`、`DangerConfirm`（Chromium 上断言焦点与读屏区） |
| 操作表单的「必填」不暴露、提交按钮无说明地灰着（1.3.1、3.3.2），表单是 `alertdialog` | `aria-required`，「必填」作描述，提交后才 `aria-invalid`，提交键可按并把焦点送到第一个空着的字段；除了不用填的危险确认都是 `dialog` | `test/declaredActions.test.tsx`；故事 `FormInput` |
| 批量按钮破坏结果工具栏的一个 Tab 站 | 成为工具栏的项，进方向键顺序 | `test/declaredActions.test.tsx` |

## 已知缺口

还没做的记在包的 [todo.md](https://github.com/Ahoo-Wang/Wow/blob/main/typescript/wow-view-engine/docs/design/todo.md) 里，有为什么、判据与落点；做完一条就改下表里的那一格。

* **真人读屏**：VoiceOver + Safari、NVDA + Firefox／Chrome 还没有走过。约 30 分钟的逐步清单（每个任务的按键与应听到的话、记录表与严重程度）见[读屏走查清单](https://github.com/Ahoo-Wang/Wow/blob/main/typescript/wow-view-engine/docs/design/screen-reader-walkthrough.md)。

## 逐条准则

「支持」：满足；「部分支持」：有的地方不满足，写明在哪；「不适用」：视图引擎没有这类内容，或这件事归宿主。WCAG 2.2 删除了 4.1.1 解析，不再列出。

### 1 可感知

| 准则 | 级别 | 结论 | 说明 |
|---|---|---|---|
| 1.1.1 非文本内容 | A | 支持 | 只有图标的按钮都有名字（名字与提示框同一句）；图是有名字的 `role=img`，带摘要句与数据表；面板里的图片没写 `alt` 时用面板标题 |
| 1.2.1 仅音频与仅视频（预录） | A | 不适用 | 没有音视频 |
| 1.2.2 字幕（预录） | A | 不适用 | 同上 |
| 1.2.3 音频描述或媒体替代（预录） | A | 不适用 | 同上 |
| 1.2.4 字幕（直播） | AA | 不适用 | 同上 |
| 1.2.5 音频描述（预录） | AA | 不适用 | 同上 |
| 1.3.1 信息与关系 | A | 支持 | 表格用 `th` 与 `rowheader`，表头以列名命名，图的数据表有 `caption`；表单控件有标签；地标与两级标题；分组用 `group` 并命名；声明式操作表单的必填项带 `aria-required`，「必填」是它的描述 |
| 1.3.2 有意义的顺序 | A | 支持 | DOM 顺序即阅读顺序 |
| 1.3.3 感官特征 | A | 支持 | 说明不靠形状、位置或颜色 |
| 1.3.4 方向 | AA | 支持 | 不锁定横竖屏 |
| 1.3.5 识别输入目的 | AA | 不适用 | 没有收集用户本人信息的输入框 |
| 1.4.1 颜色的使用 | A | 支持 | 状态徽章有字；涨跌带正负号；系列有图例文字与数据表，另可钉上花纹 |
| 1.4.2 音频控制 | A | 不适用 | 没有音频 |
| 1.4.3 对比度（最低） | AA | 支持 | 每套内置预设 × 亮暗都过对比度矩阵测试；宿主覆盖的颜色由宿主负责 |
| 1.4.4 调整文字大小 | AA | 支持 | 320px 宽下无整页横向滚动（相当于 1280px 下放大 400%） |
| 1.4.5 文字的图像 | AA | 支持 | 图上的字是 SVG 文字；导出的图片是下载的文件 |
| 1.4.10 重排 | AA | 支持 | 320px 宽下页面不横向滚动；数据表与图在自己的框里滚（二维内容的例外） |
| 1.4.11 非文本对比度 | AA | 支持 | 焦点环、行与卡片的焦点、菜单里键盘所在那一项的内框、边框、分隔线在内置预设下 ≥3:1（对比度矩阵与浏览器故事守着） |
| 1.4.12 文字间距 | AA | 支持 | 注入 WCAG 规定的行高、字距、词距、段距后没有文字被截掉；20px 高的徽章字形仍完整 |
| 1.4.13 悬停或聚焦时出现的内容 | AA | 支持 | 提示框聚焦也会出现，Esc 可收起、可把指针移上去、不会自己消失 |

### 2 可操作

| 准则 | 级别 | 结论 | 说明 |
|---|---|---|---|
| 2.1.1 键盘 | A | 支持 | 核心任务都能只用键盘完成（本次修了列设置复选框不可达）；图上的标记只有指针够得着，同样的操作在表格布局与筛选条上可用键盘完成 |
| 2.1.2 无键盘陷阱 | A | 支持 | 只有模态对话框困焦点，Esc 可离开 |
| 2.1.4 字符键快捷键 | A | 支持 | 没有单字符快捷键；所有键只作用于获得焦点的控件 |
| 2.2.1 可调整的时间限制 | A | 不适用 | 没有时间限制 |
| 2.2.2 暂停、停止、隐藏 | A | 支持 | 自动刷新由用户开启，随时可关 |
| 2.3.1 三次闪烁 | A | 支持 | 没有闪烁 |
| 2.4.1 跳过区块 | A | 支持 | 有名字的地标与标题；跳到主要内容的链接是宿主的 |
| 2.4.2 页面标题 | A | 不适用 | 页面标题归宿主 |
| 2.4.3 焦点顺序 | A | 支持 | 第一轮修了六处、第二轮修了分析托盘的两处与声明式操作（行主操作、「⋯」菜单、批量栏）的焦点掉到页面开头的问题；新加的筛选条件 Esc 后直接落到它的值框 |
| 2.4.4 链接目的（上下文中） | A | 支持 | 面板里的链接以文字命名，并说明在新标签页打开 |
| 2.4.5 多种方式 | AA | 不适用 | 视图引擎不是一组网页，站点导航归宿主 |
| 2.4.6 标题和标签 | AA | 支持 | 视图名、面板名、区域名都说它是什么；表头以列名命名 |
| 2.4.7 焦点可见 | AA | 支持 | 控件一种焦点画法，菜单项在边内画 `--ring`，两种主题下 ≥3:1；强制颜色下焦点、菜单项与选中都有框 |
| 2.4.11 焦点不被遮挡（最低） | AA | 支持 | 粘性表头表尾不遮焦点；列宽比内容窄时格子裁掉溢出，复制按钮整颗留在自己格里 |
| 2.5.1 指针手势 | A | 支持 | 没有多点或路径手势是唯一的路：框选可以点两下或用键盘 |
| 2.5.2 指针取消 | A | 支持 | 按钮在抬起时生效；拖动放回原处即取消 |
| 2.5.3 名字包含标签 | A | 支持 | 可及名字包含看得见的字（「订单号」→「按订单号升序排序」） |
| 2.5.4 动作启动 | A | 不适用 | 没有靠设备动作触发的功能 |
| 2.5.7 拖动 | AA | 支持 | 可排序的列表点一下抓手即可从菜单选位置；面板「⋯」里一次点击移动或缩放一步；列宽在列设置里填 |
| 2.5.8 目标尺寸（最低） | AA | 支持 | 控件 ≥24px 或满足间距例外；8px 的列宽拖动区按等价控件例外成立——列设置里的宽度框做同一件事 |

### 3 可理解

| 准则 | 级别 | 结论 | 说明 |
|---|---|---|---|
| 3.1.1 页面语言 | A | 不适用 | 页面的 `lang` 归宿主 |
| 3.1.2 局部语言 | AA | 支持 | 面与它的弹层按措辞目录写 `lang`（宿主可自己给）；数字框、日历与建议列表里第三方部件的英文已按措辞目录说；声明式操作的开始与结果按面的措辞说，用 props 传的也一样 |
| 3.2.1 获得焦点时 | A | 支持 | 获得焦点只会出现提示框 |
| 3.2.2 输入时 | A | 支持 | 记录视图的筛选要按「应用」；分析托盘的自动运行是看得见的开关；改值只更新结果，不切换上下文 |
| 3.2.3 一致的导航 | AA | 支持 | 三种工作台同一个骨架 |
| 3.2.4 一致的识别 | AA | 支持 | 同一功能同一个名字（名字都来自一份措辞目录），抓手是同一个部件 |
| 3.2.6 一致的帮助 | A | 不适用 | 视图引擎不提供帮助入口；宿主加的帮助由宿主放在一致的位置 |
| 3.3.1 错误识别 | A | 支持 | 出错的条件就地标出（`aria-invalid` 加文字）；查询失败是 `role=alert` |
| 3.3.2 标签或说明 | A | 支持 | 每个输入都有标签，规则写在控件旁；声明式操作的表单说出哪些必填，必填项空着时按提交会说出是哪一项并把焦点送过去 |
| 3.3.3 错误建议 | AA | 支持 | 错误说怎么改（「须为 1～100 的整数」） |
| 3.3.4 错误预防（法律、财务、数据） | AA | 支持 | 删除视图要确认；移除面板可撤销；离开未保存的编辑会询问 |
| 3.3.7 冗余输入 | A | 支持 | 另存为带上原名，追问带上所选的组，不要求再输一遍 |
| 3.3.8 无障碍认证（最低） | AA | 不适用 | 视图引擎没有登录 |

### 4 健壮

| 准则 | 级别 | 结论 | 说明 |
|---|---|---|---|
| 4.1.2 名称、角色、值 | A | 支持 | Chromium 的无障碍树里没有无名的交互控件；状态用 `aria-pressed`、`aria-expanded`、`aria-sort`、`aria-checked` 等表达 |
| 4.1.3 状态消息 | AA | 支持 | 结果、错误、框选、摆放、移动与列宽都播报；仪表盘改了筛选说结果，失败的面板也说；撤销提示说它去掉了什么、撤销后说已恢复；声明式操作说出开始与结果，结果句领着刷新的条数合成一句 |

## 延伸阅读

* [视图引擎](./view-engine.md)：它解决的问题与用法。
* [视图引擎的主题](./view-engine-theming.md)：覆盖颜色变量时要守的对比度。
* [设计文档](https://github.com/Ahoo-Wang/Wow/tree/main/typescript/wow-view-engine/docs/design)：焦点与播报的规则在 `ui/README.md`。
