无障碍评审输出规范:基于 talebook 前端实践的可访问性审查报告(Findings / Verification / Verdict)写作指南
无障碍评审输出规范:基于 talebook 前端实践的可访问性审查报告(Findings / Verification / Verdict)写作指南
本篇指南围绕仓库内 review-output.md 定义的可访问性(Accessibility / a11y)评审输出格式展开,完整讲解一份独立无障碍评审报告的两段式结构:按原则分组的 Findings 表格,以及 Verification 与 Verdict 收尾。文章同时结合 talebook 前端实际代码(Vue 组件中的
aria-label、role="status"/role="alert"活动区、aria-invalid错误状态、:focus-visible焦点环等)展示评审结论应如何被引用、验证并形成最终裁决。读完本文,你将能按统一格式撰写、评审并裁决无障碍问题,让评审结果可以被团队、Agent 与自动化工具直接复用。
一、这份规范在解决什么问题
无障碍(Accessibility)审查最大的痛点不是"发现不了问题",而是问题如何被记录、分级、汇总并形成可执行的结论。talebook 仓库的 .agents/skills/better-accessibility/ 目录为前端界面的可访问性工程定义了完整工作流(见 SKILL.md),而其中的 review-output.md 单独定义了独立评审(standalone review)的输出格式。
这份规范明确了两件事:
- 格式归属:当由
better-interface(跨领域界面评审编排技能,见 SKILL.md)统筹时,评审格式、严重度、合并规则、数量上限与最终裁决都由better-interface拥有;better-accessibility只负责提供领域证据与发现。而当进行一次独立(standalone)的无障碍评审时,本规范全面接管。 - 输出结构:独立评审报告严格分为两部分——Findings(发现)与 Verification and Verdict(验证与裁决)。
这套设计把"证据收集"与"格式裁决"解耦,既保证了单领域审查的专业深度,又避免了多技能合流时格式互相冲突。从仓库的 Agent 编排文件(.agents/skills/better-accessibility/agents/openai.yaml)可以看到该技能以独立 Agent 形式存在,负责产品界面的可访问性工程。
二、Findings:按原则分组的发现表
独立评审的第一部分是 Findings。规范要求:
- 按原则分组:所有已确认的发现必须按可访问性原则(Principle)归类;
- 统一表格结构:每个分组使用一张 Markdown 表格,列为 Severity、Location、Before、After、Why;
- 禁止散行写法:绝不使用独立的 "Before:" / "After:" 行,一切证据都进入表格单元格;
- 合并系统性问题:同一根因反复出现的系统性缺陷合并为一行,并在该行内列出所有受影响位置;
- 省略无发现原则:没有任何发现的原则组直接省略,不保留空表格。
2.1 Severity:三档严重度
| 级别 | 判定标准 |
|---|---|
| HIGH | 阻止任务完成、对辅助技术隐藏内容,或造成系统性无障碍失败 |
| MEDIUM | 使某个交互对用户而言明显更困难 |
| LOW | 孤立的打磨问题(isolated polish) |
这个三档刻度与 better-interface 的共享严重度一致(HIGH 还涵盖误导用户、数据丢失风险、系统性重复失败;MEDIUM 涵盖理解力/效率/适应性/一致性的实质性损害;LOW 仅限全量模式下收录的有限影响问题)。无障碍领域的 HIGH 触发条件包括:无访问名的交互控件、无可视焦点指示的可键盘聚焦控件、指针可达但键盘不可达的路径、无视 prefers-reduced-motion 的动效、320px 宽度或 200% 缩放下被裁剪/遮挡/不可达的内容、对比度不达标的正文、仅靠颜色传达的状态,以及无确认/撤销/特殊处理的破坏性操作(见 better-interface/SKILL.md 第 5 条)。
2.2 Location:证据定位
Location 列必须给出精确引用:
- 有源码工件(artifact)时:
path/to/file:line,即"文件路径:行号"; - 没有源码工件时:引用确切的界面与组件(如"设置页-设备列表-删除按钮"),而不是模糊的页面描述。
这一要求与 better-interface 的"证据优先"原则(Require Evidence)呼应:每一条发现都必须能追溯到具体的实现位置,禁止仅凭视觉观感或仅凭源码推测下结论。
2.3 Before / After:现状与可执行替代方案
- Before:展示当前实现(真实代码片段);
- After:给出可操作(actionable)的替换写法。
规范强调 After 必须是"可执行的修复",例如补上 aria-label="Close" 并把图标标记为 aria-hidden="true",而不是一句抽象的"提升可访问性"。同时,修复必须使用项目自身的风格体系(the project's own idiom),talebook 是 Vue + 组合式 API + 内联样式/Vuetify 生态,修复建议就应落在该技术栈上,而不是引入第二套样式系统(见 SKILL.md 引言)。
2.4 Why:指明违反的原则与用户影响
Why 列回答两个问题:违反了哪条可访问性原则?对真实用户(键盘用户、屏幕阅读器用户、低视力用户、触屏用户)产生了什么影响?
三、规范自带的四组示例:原则的落地形态
review-output.md 给出了四组完整示例,这四组恰好对应 SKILL 中的四条核心原则,是评审报告中最常见的四类发现。
3.1 Accessible names everywhere(访问名无处不在)
| Severity | Location | Before | After | Why |
|---|---|---|---|---|
| HIGH | src/Dialog.tsx:42 |
<button><XIcon /></button> |
Add aria-label="Close"; mark the icon aria-hidden="true" |
The icon-only control has no accessible name |
| HIGH | src/Nav.tsx:18 |
<a href="/settings"><GearIcon /></a> |
Add aria-label="Settings" |
The link destination is unavailable to screen readers |
图标独占的按钮/链接没有可访问名,屏幕阅读器只会读到空洞的"button"。修复要点:aria-label 给出名字,装饰性图标用 aria-hidden="true" 从无障碍树中剔除(绝不能加在可获得焦点的元素上,见 semantics-and-aria.md)。
3.2 Visible focus rings(可见焦点环)
| Severity | Location | Before | After | Why |
|---|---|---|---|---|
| HIGH | src/button.css:12 |
button:focus { outline: none; } |
button:focus-visible { outline: 2px solid; outline-offset: 2px; } |
Keyboard users cannot see focus |
| HIGH | src/Menu.tsx:31 |
focus:outline-none |
focus-visible:outline-2 focus-visible:outline-offset-2 |
Menu navigation has no visible focus indicator |
焦点环应使用 :focus-visible 而非裸 :focus——键盘与辅助技术聚焦时显示,鼠标点击时通常不显示,避免视觉噪音。绝不写 outline: none 而没有可见替代(见 focus-and-keyboard.md)。
3.3 Errors that announce(可播报的错误)
| Severity | Location | Before | After | Why |
|---|---|---|---|---|
| HIGH | src/EmailField.tsx:27 |
Error shown only as border-red-500 |
Add aria-invalid="true" + aria-describedby="email-error" with inline error text |
Color alone neither explains nor announces the error |
| MEDIUM | src/SignupForm.tsx:64 |
Submit disabled until the form is valid | Keep submit enabled; on failure, focus the first invalid field | A disabled action hides what must be fixed |
错误不能只靠颜色传达:失败字段加 aria-invalid="true",用 aria-describedby 指向行内错误文本,错误信息跟随字段被屏幕阅读器播报;提交按钮保持可用,在提交时校验并把焦点移到第一个无效字段(详见 forms.md)。
3.4 Minimum hit area(最小点击区域)
| Severity | Location | Before | After | Why |
|---|---|---|---|---|
| MEDIUM | src/Toolbar.tsx:22 |
size-4 icon-only button |
Extend the hit area to 44×44px with after:absolute after:size-11 |
The target is too small for reliable touch input |
触屏目标过小导致误触。WCAG 2.5.8(AA)硬性底线是 24×24 CSS 像素,触屏上下文推荐 44×44px,桌面推荐 40×40px;可见元素可以保持小尺寸,通过伪元素扩展命中区域,且扩展区域不得与其他交互元素重叠(见 hit-areas.md)。
四、源码证据:talebook 前端的无障碍实现对照
规范要求评审的 Location 引用 path/to/file:line,而 talebook 的 Vue 组件中恰好存在大量可被评审引用的真实实现。以下是从 app/components 提取的实现事实,可作为"合格实现"的正面样本,也可作为评审定位格式的练习素材。
4.1 访问名:从 i18n 取值的 aria-label
图标按钮普遍使用 :aria-label 提供访问名,且文案来自 i18n 键(talebook 的中英文案见 app/i18n/locales/zh-CN.json 与 en-US.json):
- AnnotationPanel.vue:刷新按钮
:aria-label="t('annotations.refresh')"; - AudioJobsPage.vue:刷新
t('common.refresh');L114 打开书籍任务按钮t('audiobook.openBookJob', { title: job.book.title });L351 关闭按钮t('common.close'); - AudiobookPlayer.vue:播放/暂停按钮的访问名随状态切换
player.playing ? t('audiobook.pause') : t('audiobook.play')。
其中 AudioJobsPage.vue:114 把书名动态拼进访问名("打开书籍任务《xxx》"),正是"可访问名应描述操作与对象"的良好实践——评审中若发现类似的动态语义,应判定为合格而非误报。
4.2 活动区(live region):role="status" 与 role="alert"
动态内容更新需要播报机制。规范与 screen-readers.md 给出的选择顺序是:焦点本身移动 → aria-describedby 绑定字段 → 非紧急用 role="status"(polite)→ 紧急用 role="alert"(assertive)。talebook 组件中两者皆有:
- 加载/状态播报:
AnnotationPanel.vue:91<div role="status" aria-live="polite">、AuthorAliasPanel.vue:9、MetaList.vue:20与LibraryChipFilter.vue:69/164的role="status"; - 紧急错误播报:
BrsAccountSettings.vue:108、LibraryChipFilter.vue:129、MetaList.vue:35的role="alert"; PluginCapabilityTester.vue:101也使用了role="status"。
评审时可对照检查:常规 toast 或结果计数用 polite(role="status"),只有表单级/页面级紧急错误才允许 assertive(role="alert"),滥用 assertive 是常见失误(见 SKILL.md Common Mistakes)。
4.3 表单错误状态:aria-invalid + 行内错误
BrsAccountSettings.vue 是表单错误处理的完整样本:多个字段按校验结果动态绑定 :aria-invalid="Boolean(fieldErrors.endpoint)"(L43、L58、L73、L88),配合 role="alert" 区域播报表单级错误。这正符合"错误必须可播报、不能只靠颜色"的规范要求——评审报告中的 aria-invalid 与 aria-describedby 建议,在该组件中已有对应实现可参照。
4.4 焦点环:组件内 :focus-visible 样式
AudioJobsPage.vue 的 .job-plan-toggle:focus-visible { outline: 3px solid rgba(217,154,43,.42); outline-offset: 4px; } 与 LibraryChipFilter.vue 的 .library-filter-control:focus-visible 均使用 :focus-visible 而非裸 :focus,且自定义环带显式颜色与偏移——符合"优先保留浏览器环,自定义环必须验证与相邻颜色的对比"的原则(见 focus-and-keyboard.md)。
需要说明:以上仅是从源码结构可确认的实现事实。它们不代表这些组件通过了完整评审;按规范第 8 条(Verify What Can Be Verified),最终裁决必须基于真实运行的检查(键盘走查、可访问名检查、屏幕阅读器测试)而非代码阅读。
五、Verification and Verdict:验证与裁决
Findings 之后是报告的第二部分,包含两个强制步骤:
5.1 Verification(验证)
列出实际执行过的检查及其观察结果,包括:
- 键盘遍历(keyboard traversal):每个流程能否脱离鼠标完成;
- 可访问名检查(accessible-name inspection):每个交互控件是否播报名称、角色与状态;
- 屏幕阅读器或自动化检查(screen-reader / automated checks):适用时记录工具与结果;
- 诚实标注未验证项:如果某项检查没有运行,必须明确写出"仍需要验证什么",而不是默认通过。
这与 SKILL 的评审方法论一致——"先用纯键盘走完整条流程,再以屏幕阅读器用户身份走查:每个控件是否播报名称、角色与状态"(见 SKILL.md)。评审只读不改,验证缺口永远不能转变成一条"发现"。
5.2 Verdict(裁决)
裁决只有三种,规则明确:
| 裁决 | 触发条件 |
|---|---|
Block |
仍存在任意一条 HIGH 发现 |
Needs changes |
仅剩 MEDIUM 或 LOW 发现 |
Approve |
不再存在任何可操作(actionable)发现 |
5.3 零发现场景
当评审没有任何发现时:
- 省略所有表格(不保留空表);
- 直接声明 "No actionable accessibility findings";
- 报告验证过程与结果;
- 以
Approve结尾。
六、与 better-interface 编排的关系:谁拥有格式与裁决
规范开头特别划清了职责边界,这是报告可被多技能复用而不冲突的关键:
- 独立评审时:
review-output.md拥有格式、严重度、合并、上限与裁决; - 由
better-interface统筹时:编排技能拥有格式、严重度、合并规则、发现上限与裁决,better-accessibility只交付领域证据与发现(domain evidence and findings)。
better-interface 的编排规则进一步说明:当领域技能经由它加载时,要应用其原则与参考文档,但忽略其 Reporting 章节及其指向的 review-output.md,改用统一合并格式、共享严重度与上限;若该技能不可用,该领域标记为 Not reviewed 并写明缺失技能,不得用相邻技能顶替(见 better-interface/SKILL.md 第 3 条)。若评审范围来自版本控制(分支/PR/未提交改动),则属于 interface-review 的变更评审范畴,better-interface 不代行解析变更范围。
理解这层"编排者 vs 领域技能"的职责划分,能帮助你在实际工作流中正确选择输出模板:单领域深度审查用本规范的两段式独立报告;跨领域综合评审用 better-interface 的合并报告(含 Scope and Coverage、Considered but Rejected、Verification、Verdict 与变更评审扩展节)。
七、实操清单:按本规范产出一份评审报告
- 确定评审主体:确认是独立无障碍评审(用本格式)还是
better-interface统筹(移交编排)。 - 按原则分组:参考 SKILL.md 的 Quick Reference 确定检查维度——Focus & Keyboard、Semantics & ARIA、Forms、Screen Readers、Hit Areas、Motion & Zoom。
- 收集证据:逐条确认发现,Location 必须精确到
path/to/file:line;无源码时引用确切界面与组件。 - 合并系统性问题:同一根因的多处位置合并为一行,全部列出。
- 判定严重度:对照 HIGH/MEDIUM/LOW 定义;
better-interface的触发清单一旦命中即 HIGH。 - 补齐 Verification:记录真实执行的检查与观察结果,诚实标注未验证项。
- 给出唯一裁决:
Block/Needs changes/Approve,与剩余发现的严重度严格对应。
按照这套流程产出的报告,每一条发现都具备"原则 + 位置 + 现状 + 替代方案 + 影响"的完整证据链,验证过程可复现,裁决规则无歧义——这正是无障碍评审从"主观意见"走向"可审查、可引用、可执行"的关键。
相关文档索引
- 输出格式规范本体:.agents/skills/better-accessibility/review-output.md
- 无障碍技能总纲(14 条核心原则与常见失误表):.agents/skills/better-accessibility/SKILL.md
- 领域细则:focus-and-keyboard.md、semantics-and-aria.md、forms.md、screen-readers.md、hit-areas.md、motion-and-zoom.md
- 编排者技能(格式/严重度/裁决的另一个所有者):.agents/skills/better-interface/SKILL.md
- 源码对照样本:app/components(含 AnnotationPanel、AudioJobsPage、AudiobookPlayer、BrsAccountSettings、LibraryChipFilter、MetaList 等)