Windows 應用程式無障礙入門 ── 為 UI Automation 與合理調整做準備

· · 無障礙, UI Automation, Windows, WinForms, WPF, 合理調整, 螢幕閱讀器, 消除歧視法, 業務應用程式

「中途入職、有視覺障礙的同事,無法用螢幕閱讀器操作核心接單應用。瀏覽器與郵件沒問題,只有我們業務應用的朗讀不對勁。有辦法嗎?」── 來自客戶 IT 部門的這類諮詢正在增加。

背景之一是法律框架。2021 年消除對身心障礙者歧視法修正於 2024 年 4 月 1 日施行,對身心障礙者「提供合理調整」也成為事業的義務1 再者,開頭那種員工與公司的關係(僱用領域)屬於身心障礙者就業促進法,該法自 2016 年 4 月起就課予雇主合理調整義務2「無障礙是網站的事,跟公司內部 Windows 應用無關」這種想法,在法律與實務上都不成立了。

另一方面,從開發現場誠實地說,「不知道該做什麼」是常見位置。Windows 桌面應用的無障礙資訊比 Web 少,也沒有事後的魔法解。也不必悲觀。只要理解螢幕閱讀器讀取應用的機制(UI Automation),並掌握名稱、鍵盤、顏色的基礎,業務應用的可用性就會大幅改善。 而且其中許多改善,無論有沒有障礙,都會提高每位使用者的生產力。

本文以日本業務應用的開發者與 IT 人員為對象,從法律框架與標準的最低整理,一路連到 UI Automation 的機制、WinForms/WPF 實作、鍵盤操作、顏色與對比、驗證工具,以及現實的優先順序。

本文的流程本文結構依序從整理法律框架與標準,連到 UI Automation 的機制、WinForms 與 WPF 實作、鍵盤操作、顏色與對比、驗證工具,以及如何排優先順序整理法律框架與標準UI Automation 的機制WinForms/WPF 實作鍵盤操作顏色與對比驗證工具如何排優先順序

圖 1: 本文把法律框架到機制、實作、驗證、優先順序連成一條流程。

1. 先講結論

  • 提供合理調整自 2024 年 4 月 1 日起也是事業的義務。身心障礙者表明要除去障礙的意圖時,須在不過度負擔的範圍內對應。僱用領域在身心障礙者就業促進法,自 2016 年 4 月起就是雇主義務。12
  • 合理調整是「透過建設性對話回應個別要求」的過程;事先讓應用更好用是「環境整備」(努力義務)。完美的事先對應不是義務;重要的是不要單方面拒絕對話。1
  • 無障礙的技術準則集中在 WCAG(JIS X 8341-3:2016)。JIS X 8341-3:2016 是與 WCAG 2.0 內容相同的對應標準,W3C 的 WCAG2ICT 說明如何套用到非 Web 軟體。桌面應用可用同一套思路檢查。34
  • 螢幕閱讀器透過 UI Automation(UIA)讀取應用。UIA 樹上各元素持有的屬性──Name、ControlType 等──以及 Invoke、Value、SelectionItem 等控制模式,是朗讀與操作的材料。5
  • Name 空白的按鈕只會被念成「按鈕」。最高優先的修正是命名。WinForms 用 AccessibleName 與把 Label 關聯到 Tab 順序;WPF 用 AutomationProperties.Name/LabeledBy。67
  • 單靠鍵盤就能到達每個功能,是 WCAG 成功準則(2.1.1),同時也是熟練操作者的輸入速度本身。把 Tab 順序、快速鍵、焦點指示做好,直接連到每位使用者的效率。8
  • 文字對比以 4.5:1 以上為指引,不要只靠顏色傳達資訊。在對比主題(高對比)下,尊重系統顏色而不是寫死的顏色。89
  • 驗證把 Accessibility Insights for Windows 的 FastPass 與螢幕閱讀器實地檢查組合起來。因為坐在同一套 UIA 基礎上,這份工作也與 FlaUI 這類 UI 自動測試資產互相划算。10
  • 不必一次修所有畫面。現實順序是(1)從那位使用者在用的畫面、(2)新開發符合標準、(3)靠修共用控制項横向展開。

一句話:無障礙對應是「在 UIA 樹上公開正確的名稱與操作,並守住鍵盤與顏色的基礎」。

2. 整理法律框架與標準 ── 「變成義務」改變了什麼

2.1. 消除對身心障礙者歧視法 ── 從 2024 年 4 月起,事業也有提供合理調整的義務

消除對身心障礙者歧視法禁止行政機關與事業對身心障礙者做「不正當差別待遇」,並要求「提供合理調整」。在 2021 年(令和 3 年)修正中,事業提供合理調整從努力義務變成義務,修正法於 2024 年 4 月 1 日(令和 6 年)施行1

依內閣府傳單,提供合理調整是身心障礙者表明需要某種對應以除去社會中的障礙時,在不過度負擔的範圍內回應。而且內容因障礙特性、場面、狀況而異,因此強調身心障礙者與事業把對話疊起來、一起思考對應的「建設性對話」。單方面拒絕建設性對話,被寫成可能構成違反提供合理調整的義務。1

這裡有兩個實務區分很重要。

  1. 「事先把一切準備好」並不是變成義務的那件事。針對不特定多數身心障礙者的事先改善──手冊與訓練等軟體側、設施無障礙等硬體側──稱為「環境整備」,這是努力義務1 事先讓業務應用能用螢幕閱讀器使用,可想成環境整備的努力。環境整備走得愈遠,個別合理調整的負擔愈輕。
  2. 僱用領域不在消除對身心障礙者歧視法,而在身心障礙者就業促進法。同一份傳單也寫僱用與工作依身心障礙者就業促進法的規定。1 而該法依 2016 年 4 月(平成 28 年)施行的修正,禁止僱用上的身心障礙歧視,以及在不過度負擔範圍內提供合理調整,已課予雇主2 開頭「員工用不了業務應用」的諮詢,事實上早在 2024 年之前就已是義務領域。
合理調整與環境整備的定位一般事業與身心障礙者的關係在消除歧視法,透過建設性對話回應個別要求的合理調整自 2024 年 4 月起是義務;僱用領域自 2016 年 4 月起依就業促進法是雇主義務;事先讓應用更好用是環境整備、努力義務事業 + 障礙僱用/工作哪個場面?消除歧視法就業促進法經對話提出要求提供調整2024 年起義務提供調整2016 年起義務事先讓應用更好用環境整備努力義務

圖 2: 適用法律依場面拆開;合理調整是義務,事先修正是環境整備、努力義務。

個案在法律上怎麼處理依情況而定。本文不踏進法律解釋;從工程師被要求對應時能做什麼的視角前進。一手資料請參內閣府與厚生勞動省資料。12

2.2. JIS X 8341-3 與 WCAG ── 「Web 準則」也延伸到軟體

技術準則側集中在 JIS X 8341-3:2016。此標準是 ISO/IEC 40500:2012 的對應標準,標準本文與 W3C 的 WCAG 2.0 內容相同。3 若想具體知道「無障礙對應」由什麼組成,讀 WCAG 成功準則(現已在 WCAG 2.1/2.2 擴充)是最短路徑,WAIC 也公開日文翻譯。8

「WCAG 是 Web 內容的準則嗎?」這個問題合理,但 W3C 在稱為 WCAG2ICT(Guidance on Applying WCAG 2 to Non-Web Information and Communications Technologies)的 Group Note 裡,整理了如何把 WCAG 2.0/2.1/2.2 成功準則套用到非 Web 文件與軟體4 也就是說,「文字替代」「對比」「鍵盤操作」「顏色不是唯一手段」這類思路,可用與 Web 同一框架套到 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) 的無障礙基礎。UIA 讓螢幕閱讀器這類輔助科技取得 UI 資訊、用標準輸入以外的手段操作 UI,並在應用側(提供者)與輔助科技側(用戶端)之間仲介。5

UIA 的世界可理解成下面三件套。5

要素 角色 代表性例子
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 上主要的螢幕閱讀器包括 Windows 內建的旁白、免費開源的 NVDA11 以及在日本廣泛使用的商業產品 PC-Talker。朗讀風格各異,但讀桌面應用 UI 的主路徑每種都是 UIA。因此應用側的對應不是「支援特定螢幕閱讀器」,而是集中在向 UIA 公開正確資訊

主要螢幕閱讀器的共同路徑若應用向 UIA 公開正確資訊,旁白、NVDA、PC-Talker 都能用同一路徑讀 UI,因此應用側對應不針對特定螢幕閱讀器,而集中在向 UIA 公開公開資訊應用UI Automation(UIA)旁白NVDAPC-Talker對應集中在向 UIA 公開

圖 5: 主要螢幕閱讀器都以 UIA 為路徑,因此應用的對應集中在向 UIA 公開。

3.3. 「Name 空白的按鈕」會被念成什麼?

一個具體例子。假設工具列有一個只顯示軟碟圖示的儲存按鈕。對視力正常的使用者,圖示傳達意義;若 Name 留空,螢幕閱讀器會把這個按鈕只念成「按鈕」。若旁邊的「開啟」與「列印」也一樣,使用者只聽到「按鈕、按鈕、按鈕」,無從知道哪個是哪個。Microsoft 的無障礙修正指南也把沒有 Name 的按鈕、只被念成「Image」的影像,列為讓使用者工作停住的代表性問題。7

幸好 WinForms 與 WPF 標準控制項一開始就有 UIA 支援,許多情況下 Name 會從文字或標籤自動決定。壞掉的通常是(1)只有圖示、沒有名稱材料、(2)沒有與標籤關聯、或(3)自訂繪製沒有把資訊放到 UIA 樹。 接下來兩章依架構看怎麼修。

朗讀壞掉的三種典型方式朗讀會在只有圖示沒有名稱材料、沒有與標籤關聯、或自訂繪製沒有把資訊放到 UIA 樹時壞掉,最後只被念成按鈕只有圖示、沒有材料Name 變成空白沒有與標籤關聯自訂繪製不輸出資訊只被念成按鈕

圖 6: 朗讀壞掉通常可歸到三種模式:名稱材料不足、關聯不足、或自訂繪製。

4. WinForms 實作 ── AccessibleName 與 Tab 順序

4.1. Text 會自動變成 Name 的控制項,以及不會的控制項

在 WinForms,Button 或 CheckBox 這類顯示文字的控制項,把 Text 屬性的值當 UIA Name。另一方面,ComboBox、ListBox、ListView、PictureBox、ProgressBar、TabControl、TextBox、TreeView 等不會把 Text 當 Name。這些需要用別的手段給名稱。6

最好維護的做法是在目標控制項的直前 Tab 順序放一個說明用 Label。若把目標控制項的 TabIndex 設成緊接在 Label 的 TabIndex 之後,該 Label 的文字會自動當 UIA Name。畫面上看得見的標籤與朗讀一致,不必管理兩次文案。612

若不能放 Label,就明確設定 AccessibleName。需要補充說明可設 AccessibleDescription,角色與外觀不同可設 AccessibleRole。13

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 的順序決定。

// An icon-only toolbar button: state the name for announcement explicitly
saveToolStripButton.AccessibleName = "Save";

// An image-only button: name + a supplementary explanation
btnSearchCustomer.AccessibleName = "Search customer";
btnSearchCustomer.AccessibleDescription = "Search the customer master by customer code or name";

// Set it directly on an input field where you cannot place a Label in the immediately preceding tab order
txtOrderNo.AccessibleName = "Order number";

// A PictureBox reused as a chart display: match the role to the reality as well
pictureBoxChart.AccessibleRole = AccessibleRole.Chart;
pictureBoxChart.AccessibleName = "Monthly order-count chart";

要注意的是,若在 Visual Studio 的屬性窗格設過一次 AccessibleName 再清掉,設計工具檔可能留下空字串設定,干擾預設名稱解析。從設計工具檔刪掉對應列。6

空字串 AccessibleName 留下的問題若在屬性窗格設過一次 AccessibleName 再清掉,設計工具檔會留下空字串設定並干擾預設名稱解析,因此從設計工具檔刪掉對應列來修設定 AccessibleName在屬性窗格清掉空字串設定留下干擾預設名稱解析從設計工具檔刪掉對應列

圖 8: 在屬性窗格清掉仍會留下空字串,因此從設計工具檔刪掉對應列來修。

4.2. 接單畫面上常見的改善

業務應用裡實際常修的地方,整理成檢查清單。

常見狀態 問題 怎麼修
只有圖示的 ToolStripButton 只被念成「按鈕」 設定 AccessibleName
TextBox 附近有 Label 但 Tab 順序散亂 輸入欄名稱空白,或變成無關名稱 把輸入欄放在 Label 的 TabIndex 正後方
用 Click 把 PictureBox 當按鈕 角色沒被傳達成按鈕,也不能從鍵盤按 換成 Button,或設 AccessibleRole/AccessibleName 加上鍵盤支援
DataGridView 欄標題空白或只有符號 念儲存格時欄的意義不清楚 在 HeaderText 設有意義的欄名
只用 Panel 分組內容,標題是影像 分不出是哪個輸入群組 用 GroupBox,或把標題做成 Label

每一項都是幾行的修正,但對螢幕閱讀器使用者,這是「用不了的畫面」與「用得了的畫面」的分叉。

5. WPF 實作 ── AutomationProperties 與 AutomationPeer

5.1. AutomationProperties.Name / LabeledBy / HelpText

在 WPF,Content 是字串的控制項(如 Button)把該內容當 UIA Name。只有圖示的按鈕(Image 或 Path)沒有 Name 材料,因此用 AutomationProperties.Name 陳述,或附近有顯示文字時用 AutomationProperties.LabeledBy 關聯。7

TextBox 有重要注意。TextBlock 的 Text 會被重用當 Name,但 TextBox 的 Text 公開在 UIA Value 屬性側,不會變成 Name。對輸入欄,用 LabeledBy 關聯顯示標籤 TextBlock 是第一候選。朗讀與畫面顯示一致,也避免管理兩次文案。14

<!-- An input field: associate the display label with LabeledBy -->
<TextBlock x:Name="OrderNoLabel" Text="Order number" />
<TextBox
    AutomationProperties.LabeledBy="{Binding ElementName=OrderNoLabel}"
    AutomationProperties.AutomationId="OrderNoTextBox" />

<!-- An icon-only button: state the name, and a supplement if needed -->
<Button
    AutomationProperties.Name="Confirm order"
    AutomationProperties.HelpText="Confirm the order being entered and allocate inventory">
    <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。

放不進 Name 的補充資訊可用 AutomationProperties.HelpText 公開。7 另外,AutomationId 是 UI 自動測試用來識別元素的識別碼,因此在畫面設計時決定命名慣例,之後會划算(深度寫在〈Windows 桌面應用程式的 UI 自動測試〉)。

5.2. 自訂控制項需要 AutomationPeer

自己畫的自訂控制項,原樣無法在 UIA 樹上公開有意義的資訊。在 WPF,於 UIElement 衍生類覆寫 OnCreateAutomationPeer,回傳 AutomationPeer 衍生類,以公開名稱、種類、模式。若繼承既有控制項,繼承對應的 Peer(ButtonBase 用 ButtonBaseAutomationPeer)就能接手已實作的行為。15

經 AutomationPeer 公開資訊的方式自訂控制項藉由覆寫 OnCreateAutomationPeer 並回傳 AutomationPeer 衍生類來公開名稱、種類、模式;若繼承既有控制項,繼承對應 Peer 並接手已實作的行為自訂控制項OnCreateAutomationPeer回傳 Peer 衍生類公開名稱、種類、模式繼承既有控制項繼承對應 Peer接手已實作的行為

圖 10: 自訂控制項從 OnCreateAutomationPeer 回傳 Peer,向 UIA 公開資訊。

// An example of a control that custom-draws line status as a coloured lamp
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 ? "Line status: online" : "Line status: offline";

    private static void OnIsOnlineChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        // Raise a UIA property-changed event the moment the value changes. Without this,
        // a screen reader keeps the old name and cannot notice the change of state
        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-equivalent if it is a status display with no operation

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

回傳名稱還不夠;值一變就用事件告訴它 也是 Peer 的工作。輔助科技沒有自己重新抓值的時機,因此不引發變更事件的實作處於「再問一次才正確」的狀態,螢幕閱讀器使用者不會被告知狀態變化。

把狀態變化告訴螢幕閱讀器的流程控制項的值一變,AutomationPeer 就引發 Name 屬性變更事件;輔助科技不會自己重新抓,因此沒有事件就停在舊名稱、無法注意到變化螢幕閱讀器AutomationPeer控制項螢幕閱讀器AutomationPeer控制項沒有事件就停在舊名稱IsOnline 值改變引發 Name 屬性變更事件朗讀新狀態

圖 11: 值的變化只有在 AutomationPeer 用變更事件告訴它時,才會到達螢幕閱讀器。

若自訂控制項有操作(能按、能改值、能選),覆寫 GetPattern 並提供 IInvokeProvider 或 IRangeValueProvider 這類模式介面。15 重點是若在共用控制項函式庫側也把 Peer 建好,每個使用它的畫面就自動被支援。那是第 9 章「横向展開」的基礎。

6. 單靠鍵盤就能到達每個功能嗎?

WCAG 成功準則 2.1.1(Keyboard)要求內容的所有功能都能透過鍵盤介面操作。8 螢幕閱讀器使用者原則上不用滑鼠,因此鍵盤到不了的功能等於不存在的功能。檢查視角如下。

視角 要確認什麼 WinForms/WPF 的主要手段
Tab 順序 Tab 鍵移動順序是否對齊視覺順序(左上 → 右下)? 整理 TabIndex、設定 TabStop
快速鍵 能否用 Alt+字母直接移到主要項目? WinForms 在 Text 用 &;WPF 在標頭用 _
捷徑 頻繁操作(儲存、搜尋、確認)有沒有獨立按鍵? 指定 Ctrl+S 等,並在功能表顯示
焦點指示 能否用眼睛跟上現在焦點在哪? 不要拿掉焦點矩形;自訂繪製時自己畫
只有滑鼠的功能 有沒有只能靠雙擊、右鍵、拖曳、懸停使用的功能? 也從功能表或按鍵提供同一功能
對話方塊 Enter=預設按鈕、Esc=取消是否有效? AcceptButton/CancelButton、IsDefault/IsCancel

WinForms 無障礙逐步解說也把在輸入欄直前 Tab 順序放標籤、以及在使用者想移到的控制項與功能表放快速鍵,列為基礎。12

想強調的是,這不是「為障礙支援多付的成本」。在接單這類例行工作裡,手能不能離開原位就完成輸入,原樣決定操作者的吞吐量。散亂的 Tab 順序或必須用滑鼠的操作,是每天從每位使用者生產力削一點的缺陷。無障礙對應與鍵盤效率,只是同一份工作的兩個名字(依使用環境的優先順序,也見〈Windows 應用程式中 UX 設計的思考方式〉)。

把鍵盤整理好的雙重效果把 Tab 順序、快速鍵、焦點指示做好,一次產生兩種效果──輔助科技使用者能到達功能,以及每位操作者的輸入速度──只有滑鼠能用的功能等於不存在把鍵盤整理好輔助科技使用者每位操作者的速度只有滑鼠的功能等於不存在

圖 12: 把鍵盤操作整理好,同時實現輔助科技支援與每位使用者的效率;只有滑鼠的功能等於不存在。

7. 顏色與對比 ── 4.5:1 與「顏色不是唯一手段」

7.1. 對比的指引是 4.5:1

WCAG 成功準則 1.4.3(Contrast (Minimum))要求文字與文字影像的對比至少 4.5:1,大文字至少 3:1。8 在白底上放淺灰文字的現代設計,不夠這個準則並不罕見。業務應用的使用者包括視力與色覺隨年齡改變的人,以及在工廠這類光線差的環境使用的人。在設計審查養成用對比檢查器量的習慣。

7.2. 不要只靠顏色傳達資訊

成功準則 1.4.1(Use of Color)是顏色不得作為傳達資訊的唯一視覺手段。8 業務應用的典型例子如下。

  • 錯誤列只顯示紅字 → 也提供錯誤圖示與訊息欄
  • 必填欄只靠標籤顏色 → 加上「*」或「必填」文案
  • 狀態只靠燈的顏色 → 做成顏色 + 形狀,或文案(「運轉中」「已停止」)

考量色覺多樣性,這也不是「特殊對應」,而是顯示設計的基礎。

替換只靠顏色傳達的資訊錯誤只顯示紅字改成也提供錯誤圖示與訊息欄;必填只靠標籤顏色改成加上必填文案;狀態只靠燈的顏色改成搭配形狀或文案錯誤只顯示紅字也提供圖示與文案必填只靠標籤顏色加上必填文案狀態只靠燈的顏色顏色搭配形狀或文案

圖 13: 只靠顏色傳達的典型例子,改成搭配圖示、文案、以及形狀或文字。

7.3. 跟隨對比主題(高對比)

Windows 有對比主題(舊稱高對比),切到前景與背景強烈分離的配色;使用者可選並編輯內建主題,對比大致 7:1 以上。9 應用側的原則很單純:不要把顏色寫死;尊重系統顏色

  • WinForms:若把 ForeColor/BackColor 留在預設,會使用使用者的顏色設定。自己套過顏色的地方,用 SystemInformation.HighContrast 判斷,切到以 SystemColors 為基礎的方案,並用 UserPreferenceChanged 事件跟隨設定變更。12
  • WPF/WinUI:若參照 SystemColors 類資源,會跟隨主題切換。自己用筆刷填滿的地方會成為壞掉的原因。9
跟隨對比主題顏色寫死的地方在切到對比主題時會壞,因此切到以 SystemColors 為基礎的方案並用設定變更事件跟隨;若參照系統顏色就能自動跟隨使用者的顏色寫死系統顏色參照切到對比主題顏色怎麼指定?配色壞掉自動跟隨使用者的顏色切到 SystemColors用設定變更事件跟隨

圖 14: 只有顏色寫死的地方會在對比主題下壞掉;系統顏色參照會自動跟隨。

另外,低視能使用者常用高 OS 放大(DPI 縮放),因此高 DPI 對應也是無障礙對應的一部分。在 125%–200% 版面就壞的應用,到那一點就用不了。細節見〈WinForms 的高DPI支援〉與〈WPF 高 DPI 對應〉。

8. 驗證實務 ── Accessibility Insights 與螢幕閱讀器實地檢查

8.1. Accessibility Insights for Windows

Microsoft 提供 Accessibility Insights for Windows 作為 Windows 應用的無障礙驗證工具,主要有三種用途。10

  • Live Inspect:只要把滑鼠停在元素上或用鍵盤聚焦,就能確認其 UIA 屬性(Name、ControlType、模式等)。看「這個按鈕的 Name 是什麼」的最短手段。
  • FastPass:五分鐘內偵測高影響無障礙問題的輕量檢查。缺 Name 這類能機械判斷的問題,可依新畫面盤點。
  • Troubleshooting:協助診斷與修正特定問題。從偵測到的問題可直接走到本文也引用的依架構修正指南。

Windows SDK 內含的 Inspect.exe 與 AccEvent 也能確認 UIA 樹與屬性,但定位為舊工具,現在建議移到 Accessibility Insights。10

Accessibility Insights 的三種用途Accessibility Insights for Windows 提供用 Live Inspect 確認 UIA 屬性、用 FastPass 輕量檢查高影響問題、用 Troubleshooting 協助診斷與修正;建議從 Inspect.exe 等舊工具移過來建議移過來Accessibility InsightsLive InspectFastPassTroubleshooting確認 UIA 屬性偵測高影響問題協助診斷與修正Inspect.exe 等

圖 15: Accessibility Insights 有確認、偵測、診斷三種用途,是從舊工具遷移的目的地。

8.2. 用螢幕閱讀器做實地檢查

工具自動檢查能偵測的,只有能機械判斷的問題。最後一定要用螢幕閱讀器走一遍真實業務操作。 Windows 內建旁白可用 Ctrl+Windows 鍵+Enter 立刻啟動,NVDA 可免費導入。11 檢查的訣竅是不看畫面(或關掉顯示器),只靠朗讀,試能不能完成「輸入一筆訂單並確認」這類真實工作。名稱在但朗讀順序不通、焦點逃出強制回應這類問題,只有實地才找得到。

組合工具驗證與實地檢查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

還有一件。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. 如何排優先順序 ── 不要一次修所有畫面

一次修核心系統的數百個畫面,成本與品質都不現實。我們建議的做法是下面三層。

  1. 從那位使用者在工作中使用的畫面開始修。合理調整是對當事人要求個別回應的過程。1 先讓當事人用螢幕閱讀器操作實際工作,一起找出卡在哪。許多情況下日常使用的畫面會窄到幾個到十幾個,其中致命問題(沒有名稱的按鈕、鍵盤按不到的確認按鈕)可用數天的修正解決。
  2. 讓新開發符合標準。把第 8 章的檢查清單加進 Definition of Done,新畫面從一開始就支援。不像事後修正,設計時建進去的成本增加很小。
  3. 靠修共用控制項横向展開。若在搜尋對話方塊、格線、日期輸入這類公司內部共用零件上實作預設 AccessibleName 或 AutomationPeer,會對每個使用它們的畫面一次生效。遠比逐個畫面碰更划算。
修正優先順序的三層從使用者在工作中使用的畫面開始修,用檢查清單讓新開發符合標準,並靠修共用控制項展開到每個畫面1. 從使用者在用的畫面修2. 新工作符合標準3. 用共用控制項横向展開對每個使用它們的畫面一次生效

圖 18: 不要一次修所有畫面,而是依使用中畫面、新工作、共用零件三層前進。

而且對話紀錄與技術對應一樣重要。合理調整是「個別對話與調整」的過程,不是全面滿足每個要求。與當事人一起考慮替代手段(在另一個畫面做那份工作、準備 CSV 匯出、用作業覆蓋),並對負擔過重的修正達成協議,也是建設性對話的正當結果。1 記錄要求了什麼、對應了什麼、什麼做成替代手段,成為組織善意的證明。

建設性對話與紀錄的流程透過建設性對話回應身心障礙者的要求;能對應的修正就做;負擔過重的修正與當事人一起考慮替代手段並達成協議;記錄要求了什麼、對應了什麼、什麼做成替代手段要求建設性對話負擔過重?用修正回應考慮替代手段並達成協議記錄經過

圖 19: 在建設性對話中與當事人就修正或替代手段達成協議,並把那段經過留在紀錄裡。

10. 總結

  • 隨著 2024 年 4 月施行的消除對身心障礙者歧視法修正,提供合理調整也成為事業的義務。僱用領域自 2016 年起依身心障礙者就業促進法是雇主義務。事先讓應用更好用是「環境整備」(努力義務),走得愈遠,個別對應愈輕。
  • 技術準則集中在 WCAG(JIS X 8341-3:2016),同一思路可經 WCAG2ICT 套到桌面應用。
  • 螢幕閱讀器透過 UI Automation 讀取應用。UIA 樹、屬性(Name/ControlType/AutomationId)、控制模式三件套是基礎。
  • 最高優先是 Name。WinForms 用 AccessibleName 與把 Label 關聯到 Tab 順序;WPF 用 AutomationProperties.Name/LabeledBy;自訂控制項用 AutomationPeer。
  • 單靠鍵盤就能到達每個功能是 WCAG 成功準則,同時也是每位操作者的生產力。把 Tab 順序、快速鍵、焦點指示整理好。
  • 顏色的三個基礎是對比 4.5:1、顏色不是唯一手段、在對比主題尊重系統顏色。
  • 驗證把 Accessibility Insights 的 FastPass+Live Inspect 與旁白/NVDA 實地檢查組合起來,並以新畫面檢查清單建進開發流程。
  • 不要一次修所有畫面;依使用者在用的畫面 → 新工作的標準支援 → 共用控制項横向展開的順序前進。合理調整是對話的過程,經過紀錄保護組織。

第一步我們建議挑一個主要畫面,跑 Accessibility Insights for Windows 的 FastPass,然後單靠 Tab 鍵走一遍工作。三十分鐘內,自己應用的現況會具體得令人意外。

相關文章

相關諮詢領域

小村軟體有限公司承接 WinForms/WPF 業務應用的無障礙修正(螢幕閱讀器支援、整理鍵盤操作、對比主題對應)、在共用控制項實作 AutomationPeer,以及用 Accessibility Insights 做現況診斷與排優先順序的諮詢。從「想確認員工能不能用螢幕閱讀器使用我們的應用」的階段開始即可。

參考連結

  1. Cabinet Office, Leaflet “From 1 April 2024, the provision of reasonable accommodation became an obligation”. 關於令和 3 年消除對身心障礙者歧視法修正於令和 6 年 4 月 1 日施行、事業提供合理調整成為義務;關於提供合理調整是對身心障礙者表明意圖、在不過度負擔範圍內的對應;關於建設性對話的重要性以及單方面拒絕可能構成違反義務;關於「環境整備」(針對不特定多數身心障礙者的事先改善措施)是努力義務;以及僱用與工作依身心障礙者就業促進法的規定。  2 3 4 5 6 7 8 9 10

  2. Ministry of Health, Labour and Welfare, The prohibition of discrimination against persons with disabilities in employment and the obligation to provide reasonable accommodation. 關於平成 28 年 4 月施行的身心障礙者就業促進法修正課予雇主禁止僱用上的身心障礙歧視、以及在不過度負擔範圍內提供合理調整;以及合理調整指針等相關資料。  2 3 4

  3. Web Accessibility Infrastructure Committee (WAIC), Understanding JIS X 8341-3:2016. 關於 JIS X 8341-3:2016 是 ISO/IEC 40500:2012 的對應標準,標準本文與 WCAG 2.0 內容相同;以及標準假設的網頁內容範圍。  2

  4. 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

  5. Microsoft Learn, UI Automation Specification. 關於 UI Automation 向螢幕閱讀器等輔助科技提供 UI 資訊,並讓標準輸入以外的手段能操作;以及 UIA 元素、樹、屬性、控制模式、控制類型、事件的組成。  2 3

  6. 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

  7. Microsoft Learn, WPF: Setting the accessible name on a button. 關於 Button 的 Content 預設被重用為 UIA Name;關於沒有名稱的按鈕螢幕閱讀器無法朗讀用途;以及用 AutomationProperties.LabeledBy 關聯 TextBlock、明確設定 AutomationProperties.Name。  2 3 4

  8. W3C / Web Accessibility Infrastructure Committee (WAIC) translation, Web Content Accessibility Guidelines (WCAG) 2.1 Japanese translation. 關於成功準則 1.4.3(Contrast (Minimum))文字 4.5:1、大文字 3:1;關於成功準則 1.4.1(Use of Color)不讓顏色成為唯一視覺手段;以及成功準則 2.1.1(Keyboard)所有功能的鍵盤可操作性。  2 3 4 5 6

  9. Microsoft Learn, Contrast themes. 關於對比主題使用對比大致 7:1 以上的受限調色盤;關於選內建主題並編輯顏色;以及 SystemColor 類資源定義成前景/背景配對、自動跟隨主題切換。  2 3

  10. Microsoft Learn, Accessibility testing. 關於 Accessibility Insights for Windows 的三種情境──Live Inspect(用懸停/聚焦確認 UIA 屬性)、FastPass(五分鐘內偵測高影響問題)、Troubleshooting──以及建議從 Inspect、AccEvent 等舊工具移過來。  2 3

  11. NVDA Japanese Team, NVDA Japanese edition. 關於免費開源的 Windows 螢幕閱讀器 NVDA 及其日文版的提供。  2

  12. Microsoft Learn, Walkthrough: Creating an Accessible Windows-based Application. 關於在輸入欄直前 Tab 順序放說明用 Label;關於 Text 裡用 & 的快速鍵;關於用 SystemInformation.HighContrast 判斷高對比並使用 SystemColors;關於跟隨 UserPreferenceChanged 事件;以及把視覺提示與用顏色傳達的資訊組合起來。  2 3

  13. Microsoft Learn, Providing Accessibility Information for Controls. 關於 WinForms 控制項的 AccessibleName、AccessibleDescription、AccessibleRole、AccessibleDefaultActionDescription 屬性以及如何設定。 

  14. Microsoft Learn, WPF: Setting the accessible name on an edit field. 關於 TextBlock 的 Text 被重用為 UIA Name,而 TextBox 的 Text 公開為 UIA Value;以及用 AutomationProperties.LabeledBy 把標籤 TextBlock 關聯到 TextBox,或設定 AutomationProperties.Name。 

  15. Microsoft Learn, UI Automation of a WPF Custom Control. 關於自訂控制項覆寫 OnCreateAutomationPeer 並回傳 AutomationPeer 衍生類;關於繼承對應基底控制項的 Peer 類;關於經 GetPattern 提供模式提供者;以及從 XAML 側用 AutomationProperties 屬性覆寫。  2

共用相同標籤的最新文章。能以相近的主題延伸理解。

與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。

本文連結到以下服務頁面,歡迎從最接近的入口查看。

常見問題

整理諮詢這個主題時常見的問題。

業務應用的無障礙對應是法律義務嗎?
2021 年消除對身心障礙者歧視法修正於 2024 年 4 月 1 日施行,對身心障礙者提供合理調整也成為事業的義務。合理調整是身心障礙者提出要求時,在不過度負擔的範圍內除去個別障礙的對應;事先讓應用更好用,定位為稱為「環境整備」的努力義務。僱用(員工與公司的關係)不在該法而在身心障礙者就業促進法,該法自 2016 年 4 月施行的修正起就課予雇主合理調整義務。也就是說「員工用不了業務應用」早就是義務領域。個案要做到哪裡依個別情況而定,因此要確認內閣府與厚生勞動省的一手資料,並與當事人對話後決定。
螢幕閱讀器怎麼讀 Windows 桌面應用?
旁白與 NVDA 這類螢幕閱讀器,透過稱為 UI Automation(UIA)的無障礙基礎讀取應用的 UI。應用側把畫面上的元素以 UIA 樹這種結構公開;每個元素有 Name(用途)、ControlType(種類)等屬性,以及 Invoke(按下)、Value(值)等控制模式。螢幕閱讀器把這些資訊念成「確認訂單按鈕」,並透過模式操作。標準 WinForms 與 WPF 控制項一開始就有這套機制,因此開發者的主要工作是不要讓 Name 空白、讓 UI 能用鍵盤操作,以及為自訂控制項實作資訊。
既有 WinForms 應用該從哪裡開始?
最短路徑是對目標畫面跑 Accessibility Insights for Windows 的 FastPass,盤點 Name 空白的控制項與 Tab 順序問題。修正從為只有圖示的按鈕設定 AccessibleName、把 Label 關聯到輸入欄的直前 Tab 順序、整理 TabIndex 讓它對齊視覺順序開始。然後啟動旁白或 NVDA,不看畫面走一遍真實業務操作,確認卡在哪。不必一次修所有畫面;從有人實際在用的畫面開始,新畫面用檢查清單做到符合標準,才是現實做法。
高對比(對比主題)該怎麼對應?
基準是不要把顏色寫死,並尊重系統顏色。WinForms 把 ForeColor/BackColor 留在預設或用 SystemColors,用 SystemInformation.HighContrast 判斷狀態,並用 UserPreferenceChanged 事件跟隨切換。WPF 與 WinUI 也一樣,若參照 SystemColors 類資源,會自動跟隨主題切換。同時停止「只靠顏色」傳達資訊──錯誤只顯示紅色──並搭配圖示或文字。即使在一般主題,把 WCAG 的文字對比 4.5:1 以上當指引,對光線差的現場與年長使用者也更好讀。
無障礙對應也有助於 UI 自動測試嗎?
有。FlaUI 這類 UI 自動測試工具建在螢幕閱讀器使用的同一套 UI Automation 上。為無障礙放進去的 Name、ControlType、控制模式,測試程式碼可以原樣使用;為測試設計的 AutomationId 也讓元素識別更穩。反過來說,沒有出現在 UIA 樹的自訂繪製 UI,對螢幕閱讀器與測試都看不見。無障礙與自動測試是同一套基礎的投資,因此做其中一邊也會降低另一邊的成本。

作者檔案

本文作者的個人檔案頁面。

Go Komura

小村軟體有限公司 代表

以 Windows 軟體開發、技術諮詢與故障調查為中心,在難以重現的故障調查與既有資產仍在運作的專案上具有優勢。

回到部落格一覽