Windows 应用无障碍入门——为 UI Automation 与合理便利义务化做准备

· 更新日期: · · 无障碍, UI Automation, Windows, WinForms, WPF, 合理便利, 屏幕阅读器, 消除歧视法, 业务应用

更新记录(仅首版,2026年08月20日 发布)
首次发布
引用本文(DOI(已登记存档): 10.5281/zenodo.22176507)

以下 DOI 指向先前登记的存档,内容可能与当前正文不同。引用当前正文时,请使用本页网址。

Go Komura(2026)。《Windows 应用无障碍入门——为 UI Automation 与合理便利义务化做准备》。小村软件有限公司。 https://comcomponent.com/zh-CN/blog/windows-app-accessibility-ui-automation-guide/

DOI(已登记存档)
10.5281/zenodo.22176507
DOI(上次登记版本)
10.5281/zenodo.22176508

“有视觉障碍的员工无法用屏幕阅读器使用核心的订单录入应用。浏览器和邮件他都用得很熟练,偏偏我们自家的业务应用读不出来。”——来自客户信息系统部门的这类咨询正在增多。

解决这个问题的出发点,是去看应用向辅助技术传递了什么,而不是画面看上去如何。Windows 中有一套供屏幕阅读器读取应用信息的 UI Automation(UIA)。只要理解它的机制,掌握名称、键盘、颜色这几项基础,业务应用的易用性就会大幅改善。1

从法律制度看,公司内部的 Windows 应用同样不是局外人。2021 年修订的残障者歧视消除法已于 2024 年 4 月 1 日施行,事业者也负有提供合理便利的义务。另一方面,开头那种雇用领域属于残障者就业促进法的范围,自 2016 年 4 月起就是雇主的义务。这一区别在第 2 章梳理。23

Windows 桌面应用的无障碍资料不像 Web 那样丰富,也没有事后一次性解决的办法。不过,其中大部分必要的改善,无论用户有没有障碍,都能提高所有人的生产效率。

本文面向日本的业务应用开发者和信息系统负责人。先梳理法律制度与标准、UIA 的机制,再进入 WinForms/WPF 的实现、键盘、颜色与对比度、验证以及改造的优先顺序。

本文的脉络从整理法律制度与标准到 UI Automation 的机制、WinForms 与 WPF 的实现、键盘操作、颜色与对比度、验证工具,再到如何排优先顺序,依次串起本文的结构整理法律制度与标准UI Automation 的机制WinForms/WPF 的实现键盘操作颜色与对比度验证工具如何排优先顺序

图1:本文把法律制度、机制、实现、验证和优先顺序串成一条线。

1. 先看结论

首先要掌握的是以下三点。

  1. 把个别的合理便利与事先的环境整备分开考虑。 合理便利是针对当事人的提出反复进行建设性对话,在负担不过重的范围内予以处理的过程。事业者自 2024 年 4 月起、雇用领域的雇主自 2016 年 4 月起负有该义务。事先改造应用属于“环境整备”(努力义务),与一开始就把所有画面改到完美是两回事。23
  2. 技术层面的基础,是向 UIA 公开信息,以及名称、键盘、颜色这几项基本功。 UIA 树中的 Name、ControlType,以及 Invoke、Value、SelectionItem 等模式,构成朗读和操作的素材。最优先的是命名。WinForms 用 AccessibleName 以及 Label 与 Tab 顺序的关联,WPF 用 AutomationProperties.Name/LabeledBy 来处理;同时还要整备键盘操作、以对比度 4.5:1 为参考线的配色,以及不只依赖颜色的显示。1456
  3. 验证和改造从实际业务入手。 把 Accessibility Insights 的 FastPass 与用屏幕阅读器的实地确认结合起来,按使用者实际会用的画面、新建画面、公共控件的顺序整备。这些改善对基于同一套 UIA 基础的 FlaUI 等 UI 自动化测试同样有用。7

技术标准可以围绕 WCAG 来梳理。JIS X 8341-3:2016 是与 WCAG 2.0 内容相同的一致性标准,WCAG2ICT 则给出了向非 Web 软件适用的指南。详见 2.2 节。89

如果按目的来读,请从下表指示的章节开始。

困扰与目的 需要确认的内容 阅读章节
想知道“义务化”改变了什么 合理便利、环境整备、雇用领域的区别 第 2 章
按钮或输入框读不出正确内容 UIA 的信息,以及各框架的命名方式 第 3~5 章
想不用鼠标完成业务 Tab 顺序、访问键、焦点 第 6 章
改变颜色或缩放比例后就难用 对比度、系统颜色、高 DPI 第 7 章
想诊断现有应用并确定改造范围 自动检查、实地确认、优先顺序与对话记录 第 8~9 章

用一句话概括,所谓无障碍适配,就是“向 UIA 树公开正确的名称和操作,并守住键盘与颜色的基本要求”。

图中实线表示始终成立的关系,虚线表示带条件的关系(成立条件写在详情页各关系的说明中)。关系的完整列表(共 16 条,附依据与确信度)以及主要概念的定义,汇总在知识地图详情页(日文)。数据:JSON-LD / Turtle

2. 法律制度与标准的梳理——“义务化”改变了什么

2.1. 残障者歧视消除法——2024 年 4 月起事业者也须“提供合理便利”

本节分开确认三件事:什么成了义务、事先改造如何定位、雇用领域该看哪部法律。

事业者的合理便利从努力义务变成了义务

残障者歧视消除法是一部要求行政机关等和事业者禁止对残障人士“不当的歧视性对待”,并“提供合理便利”的法律。经 2021 年(令和 3 年)修订,此前属于努力义务的事业者提供合理便利变成了法定义务,并于 2024 年(令和 6 年)4 月 1 日施行。2

内阁府的宣传册这样说明:当残障人士表达出需要消除障碍的意愿时,要在负担不过重的范围内予以处理。具体内容因障碍特性和场合、状况而异,因此本人与事业者反复对话、共同研究处理方案的“建设性对话”非常重要。宣传册中还明确写道,单方面拒绝对话有可能构成违反提供义务。2

事先的应用改造应视为“环境整备”

成为义务的并不是事先把一切都做好。 面向不特定多数残障人士,事先推进手册修订、培训、设施无障碍化等措施被称为“环境整备”,定位为努力义务。2

事先把业务应用做成屏幕阅读器可用的状态,可以看作环境整备这一侧的工作。整备得越充分,提供个别合理便利时的负担就越轻。

员工使用的场景要看残障者就业促进法

雇用与就业场景属于残障者就业促进法,而不是残障者歧视消除法。 这一区别在内阁府的宣传册中也有记载。2

根据 2016 年(平成 28 年)4 月施行的修订,残障者就业促进法已要求雇主禁止雇用领域的残障歧视,并在不构成过重负担的范围内提供合理便利。也就是说,开头那句“员工用不了业务应用”的咨询,在 2024 年之前就已经属于义务范围。3

合理便利与环境整备的定位一般事业者与残障人士的关系属于残障者歧视消除法,以建设性对话回应个别提出的合理便利自 2024 年 4 月起成为义务,雇用领域依残障者就业促进法自 2016 年 4 月起成为雇主义务,应用的事先改造则属于努力义务的环境整备事业者与残障人士雇用与就业场景哪种场景?残障者歧视消除法残障者就业促进法以建设性对话回应个别提出提供合理便利(2024 年 4 月起为义务)提供合理便利(2016 年 4 月起为义务)事先改造应用=环境整备(努力义务)

图2:场景不同,依据的法律也不同;合理便利是义务,事先改造属于努力义务的环境整备。

另外,个案在法律上如何处理因情况而异。本文不涉入法律解释,而是从被要求处理时技术人员能做什么这一视角展开。一手资料请参阅内阁府和厚生劳动省的材料。23

2.2. JIS X 8341-3 与 WCAG——“Web 的标准”也延伸到了软件

具体阅读技术标准时,以 WCAG 为主轴来梳理会更清楚。JIS X 8341-3:2016、WCAG、WCAG2ICT 之间的关系如下。869

标准与文档 定位 本文中的读法
JIS X 8341-3:2016 ISO/IEC 40500:2012 的一致性标准,标准正文与 WCAG 2.0 内容相同 掌握无障碍的技术标准
WCAG 给出成功准则的文档。从 2.0 扩展到 2.1/2.2,并有 WAIC 的日文译本 具体确认应当满足的内容
WCAG2ICT 说明如何把 WCAG 2.0/2.1/2.2 适用于非 Web 文档与软件的 W3C Group Note 把同样的思路适用于桌面应用

对于“WCAG 不是 Web 内容的标准吗”这个疑问,WCAG2ICT 起到了桥梁作用。其正式名称是 Guidance on Applying WCAG 2 to Non-Web Information and Communications Technologies。9

文本替代、对比度、键盘操作、不只依赖颜色传达信息等思路,都能以同一套框架适用于 Windows 桌面应用。第 3 章以后把它们落实到 WinForms/WPF 的实现上。

JIS X 8341-3 与 WCAG 的关系JIS X 8341-3:2016 是与 WCAG 2.0 内容相同的一致性标准,WCAG2ICT 给出把 WCAG 的成功准则适用于非 Web 软件的方法,因此 Windows 桌面应用也能用同一套框架来检查内容相同的一致性标准WCAG 2.0(W3C)JIS X 8341-3:2016WCAG2ICT适用于非 Web 软件Windows 桌面应用

图3:JIS X 8341-3:2016 是 WCAG 2.0 的一致性标准,WCAG2ICT 把同样的准则延伸到桌面应用。

3. 辅助技术读取应用的机制——UI Automation 的三件套

3.1. UIA 树、属性、控件模式

Windows 内置的 UI Automation(UIA)是介于应用侧与辅助技术侧之间的无障碍基础设施。应用侧作为“提供程序”公开 UI 的信息,屏幕阅读器等辅助技术侧作为“客户端”获取信息。通过标准输入以外的手段操作 UI,也是靠这套机制实现的。1

首先请按画面的结构、元素的性质、可执行的操作这三件套来理解。1

组成 作用 典型例子
UIA 树 以桌面为根,按窗口→控件层层相连的树形结构。辅助技术顺着这棵树掌握 UI 窗口、窗格、按钮、编辑框
属性 表示各元素性质的值 Name(用途)、ControlType(种类)、AutomationId(标识符)、IsEnabled、IsKeyboardFocusable
控件模式 按种类表示“可执行操作”的词汇 Invoke(按下)、Value(读写值)、SelectionItem(选择)、Toggle(开/关)、ExpandCollapse(展开折叠)

例如,焦点落到按钮上时朗读出的“确定订单 按钮”,大体上就是 Name 与控件种类的组合。用户下达执行指令后,辅助技术会通过 Invoke 模式按下该按钮。

也就是说,画面上画着按钮,和辅助技术能读到并操作它,是两回事。如果 Name 和模式没有正确公开,即使画面上看得见,也等同于不存在。

UI Automation 的三件套应用作为提供程序把各元素的属性和控件模式公开到 UIA 树,屏幕阅读器作为客户端朗读 Name 与 ControlType 并通过 Invoke 等模式进行操作朗读操作应用(提供程序)UIA 树属性(Name、ControlType 等)模式(Invoke、Value 等)屏幕阅读器(客户端)

图4:应用公开到 UIA 树上的属性和模式,屏幕阅读器用它们来朗读和操作。

3.2. 屏幕阅读器是 UIA 的客户端

Windows 上的主要屏幕阅读器有内置的讲述人、免费开源的 NVDA10,以及在日本国内广泛使用的商用软件 PC-Talker。

它们各自的朗读风格不同,但读取桌面应用 UI 的主要路径都是 UIA。因此应用侧要做的,不是盯着某一款屏幕阅读器,而是集中到向 UIA 公开正确的信息这一点上。

主要屏幕阅读器的共同路径只要应用向 UIA 公开正确的信息,讲述人与 NVDA 与 PC-Talker 都能沿同一条路径读取 UI,因此应用侧的工作不针对特定屏幕阅读器,而集中于向 UIA 公开信息公开信息应用UI Automation(UIA)讲述人NVDAPC-Talker工作集中于向 UIA 公开

图5:主要屏幕阅读器都以 UIA 为路径,因此应用侧的工作集中在向 UIA 公开信息。

3.3. “Name 为空的按钮”会被读成什么

假设工具栏上有一个只显示软盘图标的保存按钮。即使外观能传达用途,只要 Name 还是空的,屏幕阅读器就只会读出“按钮”。如果旁边的“打开”“打印”也是同样状态,听到的就只是“按钮、按钮、按钮”,根本区分不开。

没有 Name 的按钮,以及只被读作“Image”的图像,在微软的修复指南中也被列为会让用户工作中断的典型问题。5

WinForms/WPF 的标准控件从一开始就支持 UIA,多数情况下 Name 会由文本或标签自动确定。出问题的典型有以下三种。

典型原因 需要检查的地方
只有图标,没有可作名称的素材 是否明确指定了用于朗读的名称
没有与标签建立关联 输入框与显示标签是否建立了关联
自绘控件没有公开信息 UIA 树上是否出现了有意义的信息

接下来的两章,把这样的区分接到 WinForms 和 WPF 各自的修改方法上。

朗读失效的三种典型只有图标而没有名称素材的情况、没有与标签建立关联的情况、自绘控件没有把信息放到 UIA 树上的情况都会让朗读失效,变成只被读作按钮的状态只有图标没有素材Name 变成空没有关联标签自绘控件不公开信息只被读作按钮

图6:朗读失效大多可归结为名称素材不足、关联不足、自绘控件这三种情况。

4. WinForms 的实现——AccessibleName 与 Tab 顺序

4.1. Text 会自动成为 Name 的控件,和不会的控件

先确认该控件是否属于会用 Text 作名称的种类

在 WinForms 中,即使同样是显示文字的控件,也分成 Text 会被用作 UIA Name 的和不会被用作 Name 的两类。4

控件示例 Name 的处理
Button、CheckBox Text 属性的值会被用作 Name
ComboBox、ListBox、ListView、PictureBox、ProgressBar、TabControl、TextBox、TreeView Text 不会成为 Name,需要用别的方式赋予名称

优先使用显示标签,放不下时再设置 AccessibleName

最易维护的做法,是把说明用的 Label 放在目标控件前一个 Tab 顺序位置。只要让目标控件的 TabIndex 紧跟在 Label 的 TabIndex 之后,Label 的文本就会被用作 UIA 的 Name。这样显示与朗读一致,也不必对同一段文字做两份维护。411

放不下 Label 时,就显式设置 AccessibleName。补充说明可以用 AccessibleDescription,需要让角色贴合实际用途时还可以设置 AccessibleRole。12

WinForms 控件名称的确定方式Button 等控件的 Text 会直接成为 UIA 的 Name,TextBox 等 Text 不被转用的控件则使用放在前一个 Tab 顺序位置的 Label 文本,放不下 Label 时显式设置 AccessibleName是否是否控件Text 会成为 Name 的种类?Text 直接成为 Name前一个 Tab 顺序位置有 Label?使用 Label 的文本作为 Name显式设置 AccessibleName

图7:WinForms 的 Name 按 Text、前一个 Tab 顺序位置的 Label、AccessibleName 的顺序来决定。

// 只有图标的工具栏按钮:明确给出用于朗读的名称
saveToolStripButton.AccessibleName = "保存";

// 只有图像的按钮:名称 + 补充说明
btnSearchCustomer.AccessibleName = "检索客户";
btnSearchCustomer.AccessibleDescription = "按客户编号或姓名检索客户主数据";

// 无法在前一个 Tab 顺序位置放置 Label 的输入框,直接设置
txtOrderNo.AccessibleName = "订单编号";

// 被用来显示图表的 PictureBox:角色也要贴合实际
pictureBoxChart.AccessibleRole = AccessibleRole.Chart;
pictureBoxChart.AccessibleName = "按月订单数图表";

明明删掉了名称,却回不到默认朗读时

在 Visual Studio 的属性窗格里给 AccessibleName 设过值再删除,设计器文件中有时会只留下空字符串的赋值。如果这条赋值妨碍了默认的名称解析,请从设计器文件中删掉对应的那一行。4

AccessibleName 残留空字符串的问题在属性窗格里给 AccessibleName 设过值再删除会让设计器文件残留空字符串的赋值并妨碍默认的名称解析,因此要从设计器文件中删掉对应的那一行来修复设置 AccessibleName在属性窗格中删除残留空字符串的赋值妨碍默认的名称解析删掉设计器文件中对应的行

图8:即使在属性窗格中删除也会残留空字符串,需要删掉设计器文件中对应的行来修复。

4.2. 订单录入画面上常见的改进点

把我们在业务应用中实际经常修改的地方整理成检查清单。

常见状态 问题 修改方法
只有图标的 ToolStripButton 只被读作“按钮” 设置 AccessibleName
TextBox 附近有 Label 但 Tab 顺序混乱 输入框的名称为空,或者取到无关的名称 把输入框放在 Label 的 TabIndex 之后
把 PictureBox 当按钮用,靠 Click 触发 角色传达不出是按钮,键盘也按不了 换成 Button,或设置 AccessibleRole/AccessibleName 并补上键盘支持
DataGridView 的列标题为空或只有符号 朗读单元格时不知道该列的含义 给 HeaderText 设置有意义的列名
只用 Panel 给内容分组,标题是图片 分不清是哪一组输入项 改用 GroupBox,或把标题改成 Label

这些都只是几行的改动,但对屏幕阅读器用户来说,就是“不能用的画面”和“能用的画面”之间的分界。

5. WPF 的实现——AutomationProperties 与 AutomationPeer

5.1. AutomationProperties.Name / LabeledBy / HelpText

按钮的名称靠字符串 Content 或显式设置来给出

像 WPF 的 Button 这样 Content 为字符串的控件,其内容会被用作 UIA 的 Name。而只有 Image 或 Path 的按钮没有可作名称的素材。这时要么用 AutomationProperties.Name 显式指定,要么在附近有显示文本时用 AutomationProperties.LabeledBy 建立关联。5

在 TextBox 上要把“名称”和“输入值”分开

TextBlock 的 Text 会被转用为 Name,但 TextBox 的 Text 是公开到 UIA 的 Value 属性一侧的,不会成为 Name。即使里面已经填了值,单凭它也传达不出“这是填什么的栏位”。13

输入框的首选做法,是用 LabeledBy 关联作为显示标签的 TextBlock。这样显示与朗读一致,也避免对同一段文字做两份维护。13

<!-- 输入框:用 LabeledBy 关联显示标签 -->
<TextBlock x:Name="OrderNoLabel" Text="订单编号" />
<TextBox
    AutomationProperties.LabeledBy="{Binding ElementName=OrderNoLabel}"
    AutomationProperties.AutomationId="OrderNoTextBox" />

<!-- 只有图标的按钮:明确名称,必要时补上说明 -->
<Button
    AutomationProperties.Name="确定订单"
    AutomationProperties.HelpText="确定当前录入的订单,并分配库存">
    <Path Data="{StaticResource CheckIconGeometry}" Width="16" Height="16" />
</Button>
WPF 控件名称的确定方式Content 为字符串的控件其内容会被用作 Name,否则首选用 LabeledBy 关联附近的显示标签,都没有时显式指定 AutomationProperties.Name,而 TextBox 的 Text 公开在 Value 一侧而不是 Name是否是否控件Content 是字符串?内容成为 Name附近有显示标签?用 LabeledBy 建立关联显式设置 NameTextBox 的 Text公开到 Value 而非 Name

图9:WPF 的 Name 按 Content 字符串、LabeledBy、显式设置的顺序决定,TextBox 的 Text 不会成为 Name。

HelpText 和 AutomationId 的职责与名称不同

放不进 Name 的补充信息,用 AutomationProperties.HelpText 公开。5 AutomationId 则是在 UI 自动化测试中用于定位元素的标识符。在画面设计阶段就定好命名规则,后面写测试时会派上用场。

概括起来,Name 是用途,HelpText 是补充,AutomationId 是标识符。在自动化测试中的用法,详见“Windows 桌面应用的 UI 自动化测试”。

5.2. 自定义控件需要 AutomationPeer

自绘的自定义控件,保持原样是无法向 UIA 树公开有意义的信息的。在 WPF 中,通过重写 UIElement 派生类的 OnCreateAutomationPeer 并返回 AutomationPeer 的派生类,来公开名称、种类和模式。14

如果继承自现有控件,那么对应的 Peer 也应一并继承。例如继承自 ButtonBase 时使用 ButtonBaseAutomationPeer,就能沿用已经实现好的行为。14

AutomationPeer 公开信息的机制自定义控件通过重写 OnCreateAutomationPeer 返回 AutomationPeer 派生类来公开名称与种类与模式,继承自现有控件时则继承对应的 Peer 以沿用已经实现好的行为自定义控件OnCreateAutomationPeer返回 Peer 派生类公开名称、种类、模式继承现有控件继承对应的 Peer沿用已经实现好的行为

图10:自定义控件在 OnCreateAutomationPeer 中返回 Peer,把信息公开给 UIA。

// 用彩色指示灯自绘线路状态的控件示例
public class StatusLamp : Control
{
    public static readonly DependencyProperty IsOnlineProperty =
        DependencyProperty.Register(nameof(IsOnline), typeof(bool), typeof(StatusLamp),
            new FrameworkPropertyMetadata(false,
                FrameworkPropertyMetadataOptions.AffectsRender, OnIsOnlineChanged));

    public bool IsOnline
    {
        get => (bool)GetValue(IsOnlineProperty);
        set => SetValue(IsOnlineProperty, value);
    }

    internal static string NameFor(bool isOnline)
        => isOnline ? "线路状态:在线" : "线路状态:离线";

    private static void OnIsOnlineChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        // 在值变化的瞬间发出 UIA 的属性更改事件。没有这一步,
        // 屏幕阅读器会一直保留旧名称,察觉不到状态的变化
        if (UIElementAutomationPeer.FromElement((UIElement)d) is AutomationPeer peer)
        {
            peer.RaisePropertyChangedEvent(
                AutomationElementIdentifiers.NameProperty,
                NameFor((bool)e.OldValue), NameFor((bool)e.NewValue));
        }
    }

    protected override AutomationPeer OnCreateAutomationPeer()
        => new StatusLampAutomationPeer(this);
}

public class StatusLampAutomationPeer : FrameworkElementAutomationPeer
{
    public StatusLampAutomationPeer(StatusLamp owner) : base(owner) { }

    protected override AutomationControlType GetAutomationControlTypeCore()
        => AutomationControlType.Text; // 没有操作的状态显示相当于 Text

    protected override string GetNameCore()
        => StatusLamp.NameFor(((StatusLamp)Owner).IsOnline);
}

不只返回当前的名称,还要通知状态的变化

上面的例子把两件事组合在一起:按当前状态返回名称的处理,以及在 IsOnline 变化时发出 Name 的属性更改事件的处理。

Peer 的职责不止于返回名称,还包括在变化发生的瞬间用事件通知出去。 辅助技术自身没有重新获取值的时机,因此一旦缺少事件,实现就变成“只有被再次询问时才正确”,屏幕阅读器用户感知不到状态的变化。

把状态变化传达给屏幕阅读器的流程控件的值变化的瞬间由 AutomationPeer 发出 Name 的属性更改事件,辅助技术不会自行重新获取,因此没有事件就会停留在旧名称而察觉不到变化屏幕阅读器AutomationPeer控件屏幕阅读器AutomationPeer控件没有事件就停留在旧名称IsOnline 的值发生变化发出 Name 的属性更改事件朗读新的状态

图11:值的变化只有经 AutomationPeer 用更改事件通知,才会传到屏幕阅读器。

有操作就实现模式,并收拢到公共部件里

对于可按下、可改值、可选择的自定义控件,要重写 GetPattern,提供 IInvokeProvider、IRangeValueProvider 等模式接口。14

只要在公共控件库这一侧把 Peer 也做好,用到它的所有画面就自动具备了支持。 这就是第 9 章要讲的横向铺开的基础。

6. 能否只用键盘到达全部功能

WCAG 的成功准则 2.1.1(键盘)要求所有功能都能通过键盘接口操作。6 屏幕阅读器用户原则上不使用鼠标,因此键盘到不了的功能,就等于不存在的功能。

6.1. 检查移动、执行和当前位置

不只看 Tab 顺序,还要确认主要操作能否执行、当前焦点是否看得出来。

观察点 需要确认的内容 WinForms / WPF 的主要手段
Tab 顺序 Tab 键的移动顺序是否与视觉排列(左上→右下)一致 整理 TabIndex、设置 TabStop
访问键 能否用 Alt+字母直接跳到主要项目 WinForms 在 Text 中加 &,WPF 在标题中加 _
快捷键 高频操作(保存、检索、确定)是否有独立按键 分配 Ctrl+S 等,并在菜单上标出
焦点显示 能否用眼睛追踪焦点当前在哪里 不要去掉焦点框,自绘时自行绘制
仅鼠标可用的功能 是否存在只能靠双击、右键、拖放、悬停才能使用的功能 在菜单和按键上并设同样的功能
对话框 Enter=默认按钮、Esc=取消是否有效 AcceptButton/CancelButton、IsDefault/IsCancel

微软的 WinForms 无障碍指南中,也把“把标签放在输入框前一个 Tab 顺序位置”“给用户想跳转的控件和菜单加上访问键”列为基本做法。11

6.2. 整备键盘操作也能提升所有用户的录入效率

这并不只是“为残障用户付出的额外成本”。在订单录入这类定型业务中,能否不把手离开基准键位就完成录入,直接决定操作员的处理件数。

Tab 顺序混乱、必须用鼠标的操作,都是每天一点点侵蚀全体用户生产效率的缺陷。无障碍适配与键盘效率优化,只是同一件工作的两个叫法。按使用环境排优先顺序的内容,也请参阅“Windows 应用 UX 设计”。

整备键盘操作的双重效果整备 Tab 顺序与访问键与焦点显示,能同时带来辅助技术用户可以到达功能和全体操作员录入速度提升这两种效果,而只能用鼠标的功能等同于不存在的功能整备键盘操作辅助技术用户可以使用全体操作员的录入速度仅鼠标可用的功能等同于不存在的功能

图12:整备键盘操作能同时实现辅助技术适配和全员提效,而仅鼠标可用的功能等于不存在。

7. 颜色与对比度——4.5:1 与“不只依赖颜色”

7.1. 对比度的参考线是 4.5:1

WCAG 的成功准则 1.4.3(对比度(最低))要求文本和文字图像的对比度至少为 4.5:1,大号文字的对比度至少为 3:1。6

把浅灰色文字放在白色背景上的设计,跌破这条标准并不少见。请把视力、色觉随年龄变化的用户,以及在工厂这类照明条件差的场所使用的用户也考虑进来,养成在设计评审时用对比度检查工具实测的习惯。

7.2. 不要只用颜色传达信息

成功准则 1.4.1(颜色的运用)规定,颜色不能成为传达信息的唯一视觉手段。6 业务应用中的典型例子如下。

只靠颜色传达的状态 并用的手段
用红色文字标出错误行 错误图标与消息列
用标签颜色标出必填项 加上“*”或“必填”字样
用指示灯颜色表示状态 颜色配合形状,或加上“运行中”“已停止”等文字

考虑到色觉的多样性,这同样不是“特别处理”,而是显示设计的基本功。

换成不只依赖颜色的信息传达只用红色文字标出错误的显示要换成并设错误图标与消息列,只用标签颜色标出必填项的显示要加上必填字样,只用指示灯颜色表示状态的显示要并用形状或文字错误只用红色文字并设图标与文字说明必填只用标签颜色加上必填字样状态只用指示灯颜色颜色并用形状或文字

图13:只靠颜色传达的典型例子,要换成并用图标、文字说明、形状或文字。

7.3. 跟随对比度主题(高对比度)

Windows 的对比度主题(原来的高对比度)是一种把前景与背景强烈分离的配色。内置主题的设计目标大致是 7:1 以上的对比度,用户可以选择和编辑。15

应用侧要做的是不把颜色写死,尊重系统颜色。各框架的做法如下。

框架 基本配色 有自定义配色时的检查
WinForms 让 ForeColor/BackColor 保持默认,使用用户的配色设置 用 SystemInformation.HighContrast 判断后切换到基于 SystemColors 的配色,并用 UserPreferenceChanged 跟随设置变更
WPF/WinUI 引用 SystemColors 系列资源,跟随主题切换 检查用自定义画刷填充的地方是不是显示错乱的原因

WinForms 的具体设置请参阅微软的指南,主题配色请参阅对比度主题的资料。1115

跟随对比度主题把颜色写死的地方在切换到对比度主题时会显示错乱,因此要改成基于 SystemColors 的配色并用设置变更事件跟随,只要引用系统颜色就能自动跟随用户的配色写死引用系统颜色切换到对比度主题颜色是怎么指定的?配色错乱自动跟随用户的配色改用 SystemColors用设置变更事件跟随

图14:只有把颜色写死的地方会在对比度主题下错乱,引用系统颜色则自动跟随。

高 DPI 下不错乱同样属于这项检查

低视力用户常常把操作系统的缩放比例(DPI 缩放)调高来使用,因此适配高 DPI 也是无障碍工作的一部分。在 125%~200% 下布局就错乱的应用,在这种使用环境里等于不能用。

具体的处理方法请参阅“WinForms 的高 DPI 适配”“WPF 的高 DPI 适配”。

8. 验证实务——Accessibility Insights 与屏幕阅读器实地确认

8.1. Accessibility Insights for Windows

微软提供的 Accessibility Insights for Windows 可以按目的选择三种用法。7

用法 能确认什么 使用场合
Live Inspect 悬停或键盘聚焦的元素的 UIA 信息(Name、ControlType、模式等) 用最短路径查清“这个按钮的 Name 是什么”
FastPass 在 5 分钟内检出高影响问题的轻量检查。排查 Name 缺失等可机械判定的问题 对每个新画面盘点问题
Troubleshooting 协助诊断和修复特定问题,可从检出的问题进入各框架的修复指南 查清检出问题的修改方法

Windows SDK 中附带的 Inspect.exe 和 AccEvent 也能查看 UIA 树和属性,但它们被定位为旧版工具,目前推荐迁移到 Accessibility Insights。7

Accessibility Insights 的三种用法Accessibility Insights for Windows 提供用 Live Inspect 查看 UIA 属性、用 FastPass 做高影响问题的轻量检查、用 Troubleshooting 协助诊断与修复,并推荐从 Inspect.exe 等旧版工具迁移过来推荐迁移Accessibility InsightsLive InspectFastPassTroubleshooting查看 UIA 属性检出高影响的问题协助诊断与修复Inspect.exe 等

图15:Accessibility Insights 有查看、检出、诊断三种用法,也是旧版工具的迁移去处。

8.2. 用屏幕阅读器做实地确认

通过了自动检查,和能完成实际业务,是两回事。 工具能检出的只有可机械判定的问题,因此最后一定要用屏幕阅读器把业务操作走一遍。

首先用 Ctrl+Windows 键+Enter 启动讲述人,或者装上免费的 NVDA。10 然后定下“录入并确定一笔订单”这样的代表性任务,不看画面,或者干脆关掉显示器,试试能否只靠朗读完成。

即使都配好了名称,朗读顺序杂乱无章、焦点跑到模态窗口外面这类问题,也只有通过这样的实地确认才能发现。

工具验证与实地确认的组合FastPass 等自动检查能检出的只有可机械判定的问题,其余要用屏幕阅读器把实际业务操作走一遍,在实地发现朗读顺序和焦点的问题工具的自动检查可机械判定的问题还剩下检不出的问题用屏幕阅读器实地确认把业务操作走一遍朗读顺序和焦点的问题

图16:自动检查盘点机械性的问题,其余靠屏幕阅读器的实地确认发现。

8.3. 纳入开发流程,以及与 UI 自动化测试的相乘效果

为了不让验证依赖个人,建议把下面这份检查清单纳入新画面的评审项目。

# 检查项 手段
1 FastPass 零错误 Accessibility Insights
2 所有输入框和按钮都有 Name Live Inspect
3 只用 Tab 键就能到达全部功能 手动
4 Enter/Esc 和主要快捷键有效 手动
5 文本对比度在 4.5:1 以上 对比度检查工具
6 对比度主题下不错乱 切换主题后目视
7 200% 缩放下不错乱 改显示设置后目视
8 能用屏幕阅读器完成代表性任务 讲述人/NVDA

把整备好的 UIA 也用到自动化测试上

FlaUI 等 UI 自动化测试与屏幕阅读器建立在同一套 UIA 基础之上。为无障碍而整备的 Name 和模式会成为测试代码的零件,为测试而设计的 AutomationId 也让 Live Inspect 中的调试更轻松。

反过来,不出现在 UIA 树上的 UI,测试和辅助技术都看不见。无障碍与可测试性是同一笔投资的两面。 详见“Windows 桌面应用的 UI 自动化测试”。

无障碍与 UI 自动化测试的相乘效果屏幕阅读器与 FlaUI 等 UI 自动化测试以同一套 UIA 为基础,因此整备好的 Name 和模式两边都能使用,不出现在 UIA 树上的 UI 两边都看不见整备 UIA 树屏幕阅读器能读UI 自动化测试能用同一笔投资的两面不出现在 UIA 上的 UI两边都看不见

图17:由于处在同一套 UIA 基础之上,整备 UIA 树对辅助技术和 UI 自动化测试都见效。

9. 如何排优先顺序——不要一次修完所有画面

对有几百个画面的核心系统做一次性改造,无论成本还是质量都不现实。我们推荐按下面三个阶段推进。

9.1. 从该用户业务中实际使用的画面改起

合理便利是针对当事人的提出逐案回应的过程。2 先请本人用屏幕阅读器操作实际业务,和他一起找出卡住的地方。

多数情况下,日常业务用到的画面能收敛到几个到十几个。其中的致命问题,例如没有名称的按钮、键盘按不了的确定按钮,往往几天的修改就能解决。

9.2. 新开发的部分默认就做到位

把第 8 章的检查清单加入完成的定义(Definition of Done)。方针是新画面从一开始就按已适配的状态来做。与事后改造不同,在设计阶段就纳入进去,增加的成本很有限。

9.3. 通过改造公共控件横向铺开

给公司内公用的检索对话框、网格、日期输入等,实现 AccessibleName 的默认值和 AutomationPeer。只要改好公共部件,用到它的所有画面都会一次性受益。这比一个个改单独画面性价比高得多。

改造优先顺序的三段式先从用户业务中使用的画面改起,新开发的部分用检查清单做成标准适配,再通过改造公共控件向全部画面横向铺开1. 从用户使用的画面改起2. 新开发部分按标准适配3. 用公共控件横向铺开用到它的所有画面一次性受益

图18:不是一次性全量改造,而是按在用画面、新增部分、公共部件这三段推进。

9.4. 不只记录改造内容,还要记录对话的经过

与技术处理同等重要的,是对话的记录。合理便利是通过对话逐案调整的过程,而不是把所有诉求全部满足。

对于负担过重的改造,与本人一起研究并达成一致,采用在别的画面完成该业务、提供 CSV 导出、用运维流程弥补等替代手段,同样是建设性对话的正当结果。2

把对方提出了什么、做了哪些处理、用什么作为替代手段记录下来,就是组织层面诚实态度的证明。

建设性对话与记录的流程对残障人士提出的诉求以建设性对话回应,能做的改造就实施,负担过重的改造则与本人研究替代手段并达成一致,并记录对方提出了什么与做了哪些处理与用了什么替代手段否是诉求建设性对话负担是否过重?用改造来处理研究替代手段并达成一致记录经过

图19:建设性对话中与本人就改造还是替代手段达成一致,并把经过留成记录。

10. 总结

把法律制度、技术和推进方式分开看,切入点就出来了。

在法律制度方面,事业者的合理便利自 2024 年 4 月起、雇用领域雇主的合理便利自 2016 年起成为义务。事先改造应用属于“环境整备”(努力义务),推进得越充分,逐案处理就越轻松。对话的经过也请记录下来。

在技术方面,以 WCAG(JIS X 8341-3:2016)为主轴,通过 WCAG2ICT 来检查桌面应用。基础是 UIA 树、属性(Name/ControlType/AutomationId)和控件模式。最优先的命名,WinForms 用 AccessibleName 以及 Label 与 Tab 顺序,WPF 用 AutomationProperties.Name/LabeledBy,自定义控件用 AutomationPeer 来实现。

在此基础上,整理 Tab 顺序、访问键和焦点显示,使全部功能只用键盘就能到达。颜色以对比度 4.5:1 为参考线,不只依赖颜色,在对比度主题下尊重系统颜色。这些同样是能提升全体操作员生产效率的改善。

推进顺序是:用户在用的画面、新增部分的标准适配、公共控件的横向铺开。请把 Accessibility Insights 的 FastPass、Live Inspect 与讲述人/NVDA 的实地确认结合起来,作为新画面的检查清单纳入开发流程。

作为第一步,推荐挑一个自家的主力画面,先运行一次 Accessibility Insights for Windows 的 FastPass,再只用 Tab 键把业务走一遍。只要 30 分钟,就能出乎意料地具体看清自家应用现在所处的位置。

相关文章

相关咨询领域

小村软件(KomuraSoft LLC)承接 WinForms/WPF 业务应用的无障碍改造(屏幕阅读器适配、键盘操作整备、对比度主题适配)、为公共控件实现 AutomationPeer,以及用 Accessibility Insights 做现状诊断与优先级排序方面的咨询。哪怕只是“想确认一下员工能不能用屏幕阅读器使用我们的应用”这个阶段,也欢迎联系。

参考链接

  1. Microsoft Learn, UI Automation Specification。关于 UI Automation 向屏幕阅读器等辅助技术提供 UI 信息并使标准输入以外的手段也能操作,以及 UIA 元素、树、属性、控件模式、控件类型、事件的构成。 ↩ ↩2 ↩3 ↩4

  2. 内阁府, 宣传册《自令和 6 年 4 月 1 日起,提供合理便利成为义务》。关于令和 3 年修订的残障者歧视消除法于令和 6 年 4 月 1 日施行、事业者提供合理便利成为义务,合理便利是对残障人士表达的意愿在负担不过重的范围内予以处理,建设性对话的重要性以及单方面拒绝可能构成违反义务,面向不特定多数残障人士的事前改善措施“环境整备”属于努力义务,以及雇用与就业依残障者就业促进法的规定等内容。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9

  3. 厚生劳动省, 雇用领域中对残障人士的歧视禁止与合理便利提供义务。关于平成 28 年 4 月施行的修订版残障者就业促进法要求雇主禁止雇用领域的残障歧视,并在不构成过重负担的范围内提供合理便利,以及合理便利指针等相关资料。 ↩ ↩2 ↩3 ↩4

  4. Microsoft Learn, WinForms: Setting the accessible name on a control。关于部分控件的 Text 会被转用为 UIA Name,而 ComboBox、ListBox、ListView、PictureBox、ProgressBar、TabControl、TextBox、TreeView 等不会被转用;把目标控件放在 Label 的 TabIndex 之后可让 Label 的文本被用作 Name;以及显式设置 AccessibleName 和空字符串残留在设计器文件中的问题。 ↩ ↩2 ↩3 ↩4

  5. Microsoft Learn, WPF: Setting the accessible name on a button。关于 Button 的 Content 默认会被转用为 UIA Name、没有名称的按钮会让屏幕阅读器读不出用途,以及用 AutomationProperties.LabeledBy 与 TextBlock 建立关联和显式设置 AutomationProperties.Name。 ↩ ↩2 ↩3 ↩4

  6. W3C / 网页无障碍基础委员会(WAIC)译, Web Content Accessibility Guidelines (WCAG) 2.1 日文译本。关于成功准则 1.4.3(对比度(最低))的文本 4.5:1、大号文字 3:1,成功准则 1.4.1(颜色的运用)不得把颜色作为唯一的视觉手段,以及成功准则 2.1.1(键盘)要求所有功能都可用键盘操作。 ↩ ↩2 ↩3 ↩4 ↩5

  7. Microsoft Learn, Accessibility testing。关于 Accessibility Insights for Windows 的 Live Inspect(通过悬停/聚焦查看 UIA 属性)、FastPass(在 5 分钟内检出高影响问题)、Troubleshooting 这三种场景,以及推荐从 Inspect、AccEvent 等旧版工具迁移。 ↩ ↩2 ↩3

  8. 网页无障碍基础委员会(WAIC), JIS X 8341-3:2016 解说。关于 JIS X 8341-3:2016 是 ISO/IEC 40500:2012 的一致性标准、标准正文与 WCAG 2.0 内容相同,以及该标准所设想的网页内容范围。 ↩ ↩2

  9. W3C, Guidance on Applying WCAG 2 to Non-Web Information and Communications Technologies (WCAG2ICT)。关于说明如何把 WCAG 2.0/2.1/2.2 的原则、指南、成功准则适用于非 Web 文档及软件的 W3C Group Note。 ↩ ↩2 ↩3

  10. NVDA 日语团队, NVDA 日语版。关于免费开源的 Windows 屏幕阅读器 NVDA 及其日语版的提供情况。 ↩ ↩2

  11. Microsoft Learn, Walkthrough: Creating an Accessible Windows-based Application。关于把说明用 Label 放在输入框前一个 Tab 顺序位置、用 Text 中的 & 设置访问键、用 SystemInformation.HighContrast 判断高对比度并使用 SystemColors、跟随 UserPreferenceChanged 事件,以及对用颜色传达的信息并用视觉线索。 ↩ ↩2 ↩3

  12. Microsoft Learn, Providing Accessibility Information for Controls。关于 WinForms 控件的 AccessibleName、AccessibleDescription、AccessibleRole、AccessibleDefaultActionDescription 各属性及其设置方法。 ↩

  13. Microsoft Learn, WPF: Setting the accessible name on an edit field。关于 TextBlock 的 Text 会被转用为 UIA Name 而 TextBox 的 Text 是作为 UIA Value 公开的,以及应给 TextBox 用 AutomationProperties.LabeledBy 关联标签用 TextBlock,或设置 AutomationProperties.Name。 ↩ ↩2

  14. Microsoft Learn, UI Automation of a WPF Custom Control。关于自定义控件通过重写 OnCreateAutomationPeer 返回 AutomationPeer 派生类、继承与基类控件对应的 Peer 类、用 GetPattern 提供模式提供程序,以及用 AutomationProperties 附加属性从 XAML 侧覆盖。 ↩ ↩2 ↩3

  15. Microsoft Learn, Contrast themes。关于对比度主题使用对比度大致在 7:1 以上的受限调色板、内置主题的选择与颜色编辑,以及 SystemColor 系列资源以前景与背景成对定义并自动跟随主题切换。 ↩ ↩2

共享相同标签的最新文章。可以围绕相近的主题进一步加深理解。

与本文相近的主题页面。以本文为起点,可以进一步了解相关服务和其他文章。

本文与以下服务页面相关联,欢迎从最接近的入口查看。

常见问题

汇总了咨询这一主题时常见的问题。

业务应用的无障碍适配是法律规定的义务吗?
2021 年修订的残障者歧视消除法于 2024 年 4 月 1 日施行,事业者也负有向残障人士提供合理便利的义务。合理便利是指当残障人士提出要求时,在负担不过重的范围内消除个别障碍的处理;而事先把应用改造得更好用,被定位为“环境整备”这一努力义务。另外,员工与公司之间这种雇用领域不属于残障者歧视消除法,而属于残障者就业促进法,该法经 2016 年 4 月施行的修订已要求雇主提供合理便利。也就是说,“员工用不了业务应用”这种场景,早就在义务范围之内。具体做什么、做到什么程度取决于个别情况,因此要先确认内阁府和厚生劳动省的一手资料,再通过与当事人的对话来决定。
屏幕阅读器是怎样朗读 Windows 桌面应用的?
讲述人、NVDA 等屏幕阅读器通过名为 UI Automation(UIA)的无障碍基础设施读取应用的 UI。应用侧以 UIA 树这种结构公开画面上的元素,每个元素都带有 Name(用途)、ControlType(种类)等属性,以及 Invoke(按下)、Value(值)等控件模式。屏幕阅读器把这些信息朗读成“确定订单 按钮”,并通过模式来操作。WinForms 和 WPF 的标准控件从一开始就具备这套机制,因此开发者的主要工作是:不要让 Name 为空、保证能用键盘操作、为自定义控件实现信息公开。
对已有的 WinForms 应用,最先应该从哪里入手?
最快的路径是先对目标画面运行 Accessibility Insights for Windows 的 FastPass,盘点出 Name 为空的控件和 Tab 顺序问题。修改从这几件事开始:给只有图标的按钮设置 AccessibleName、把 Label 放到输入框前一个 Tab 顺序位置以建立关联、整理 TabIndex 使其与视觉排列一致。在此基础上启动讲述人或 NVDA,不看画面把实际业务操作走一遍,确认卡在哪些地方。不必一次修完所有画面,从确实有人使用的画面着手,新画面则用检查清单做成标准适配,这样才现实。
适配高对比度(对比度主题)要做些什么?
基本原则是不把颜色写死,尊重系统颜色。WinForms 可以让 ForeColor/BackColor 保持默认或改用 SystemColors,用 SystemInformation.HighContrast 判断状态,并用 UserPreferenceChanged 事件跟随切换。WPF 和 WinUI 只要引用 SystemColors 系列资源,也会自动跟随主题切换。同时要停止只用红色表示错误这类“只依赖颜色”的信息传达,并搭配图标或文字说明。即使在普通主题下,把文本对比度 4.5:1 以上这一 WCAG 标准作为参考线,对照明条件差的现场和年长用户也更易读。
无障碍适配对 UI 自动化测试也有帮助吗?
有帮助。因为 FlaUI 等 UI 自动化测试工具与屏幕阅读器建立在同一套 UI Automation 基础之上。为无障碍而整备的 Name、ControlType 和控件模式可以直接被测试代码使用,为测试而设计的 AutomationId 则让元素定位更稳定。反过来,不出现在 UIA 树上的自绘 UI,屏幕阅读器和测试都看不见。无障碍与自动化测试是对同一套基础的投资,因此整备其中一边,另一边的成本也会下降。

作者简介

本文作者的个人简介页面。

Go Komura

小村软件有限公司 代表

以 Windows 软件开发、技术咨询与故障排查为中心,擅长难以复现的故障调查,以及既有资产仍在运行的项目。

返回博客列表