iT邦幫忙

2026 iThome 鐵人賽

DAY 30
0
佛心分享-SideProject30

30 天開發一款真正能每天使用的散步 App系列 第 30

Accessibility——功能做完了,但真的每個人都能用嗎?

  • 分享至 

  • xImage
  •  

前面 29 天,從 GPS 記錄、背景定位,到推薦路線、離線同步、Widget,再到最後的 AI 分析,一開始預計要做的功能全部做完了。

最後一天想分享一個完全不一樣的內容:Accessibility,簡稱 a11y,中文通常稱為「無障礙」或「可訪問性」。

如果使用者看不到畫面上的資訊,這些功能還能不能使用?

我在很久之前看過一個影片,是採訪幾位視障程式設計師,看看他們平常是怎麼 coding 的:我采访了几位盲人程序员,看看他们是怎么写代码的【差评君】

影片裡有提到,視障者很依賴螢幕閱讀器(例如 iOS 的 VoiceOver、Android 的 TalkBack)。

如果 App 沒有為元件提供適當的說明,即使螢幕閱讀器可以讀到這個元件,也可能不知道它到底是做什麼的。

這也讓我開始思考:

如果今天 App 是由一個看不到畫面的使用者操作,現在做好的這些功能還能不能正常使用?

無障礙標準

目前常見的無障礙標準是 WCAG(Web Content Accessibility Guidelines),主要由 W3C 制定。

WCAG 的核心可以簡單分成四個原則:

  • 可感知:資訊需要能被使用者感知
  • 可操作:介面與功能需要可以操作
  • 可理解:資訊與操作方式需要容易理解
  • 穩健性:內容需要能被不同的輔助工具正確解析

https://www.w3.org/WAI/standards-guidelines/wcag/glance/

這些原則不只適用於網站,Mobile App 也可以參考。

平常怎麼檢查 Accessibility?

不同平台都有自己的工具:

Android

Android 可以使用 Accessibility Scanner,掃描 App 後會列出一些可能需要改善的地方。

Accessibility Scanner

iOS

macOS 本身就有 Accessibility Inspector,可以檢查 iOS App 的 Accessibility 資訊。

Web

Chrome、Firefox、Safari、Edge 的開發者工具都有 Accessibility 相關功能。

自己使用下來,我覺得 Firefox 的 Accessibility 工具做得滿完整,除了檢查元素的 Accessibility Tree,也可以查看 Tab 順序、模擬色盲等。

Firefox

Chrome

Chrome 可以在 Elements 裡查看元素的 Accessibility 資訊,也可以使用 Lighthouse 做 Accessibility 評估。

另外 Chrome 的 Color Picker 也會直接顯示文字對比度。

Safari

Safari 的 Elements 裡也可以查看 Accessibility 屬性,另外還有專門的 Accessibility 審查工具。

也可以搭配瀏覽器擴充功能進行檢查。

開發時常見的 Accessibility 問題

文字對比度

文字和背景的對比度太低,會讓視力不好或有色覺障礙的使用者更難閱讀。

例如 WebAIM 的 Contrast Checker 可以直接檢查對比度,並告訴你是否符合 WCAG AA / AAA。

來源:文字背景对比度 contrast ratio 的计算公式
對比度計算工具:https://webaim.org/resources/contrastchecker/

如果想自己理解計算方式,可以參考相對亮度與對比度公式:

L = 0.2126 * R / 255
  + 0.7152 * G / 255
  + 0.0722 * B / 255

對比度 = (L1 + 0.05) / (L2 + 0.05)

另外也有一些配色網站可以直接參考:

觸控目標

按鈕太小也會影響操作。

一般可以參考:

  • iOS:至少 44pt
  • Android:至少 48dp

React Native Pressable 可以使用 hitSlop 增加實際可點擊範圍。

<Pressable
  hitSlop={{ top: 12, bottom: 12, left: 12, right: 12 }}
  onPress={() => console.log('onPress')}
>
  <Text>Pressable</Text>
</Pressable>

例如 Icon 本身只有 24px,也可以透過 hitSlop 讓實際點擊範圍更大。

Accessibility Label

對 React Native 來說,最常接觸的幾個 Accessibility props 是:

  • accessible
  • accessibilityLabel
  • accessibilityHint
  • accessibilityRole
  • accessibilityState
  • accessibilityValue

例如:

<View
  accessibilityLabel="view1"
  accessibilityHint="我是 view1"
>
  // ...
</View>

使用螢幕閱讀器時,就能知道這個元件叫做 view1,以及它的用途。

這些 API 在 Android 和 iOS 上會有一些差異,實際開發時還是需要搭配官方文件確認。

把 Accessibility 實際套到 App

前面了解一些基本概念之後,就可以回到今天真正要做的事情。

這次沒有把所有畫面重新檢查一遍,而是直接拿 App 最重要的散步流程,用 旁白(VoiceOver) 和 螢幕閱讀器(TalkBack) 實際操作:

開始散步
    ↓
取得 GPS
    ↓
開始記錄
    ↓
暫停 / 繼續
    ↓
導航
    ↓
偏離路線
    ↓
完成散步
    ↓
結束

結果確實找到一些平常用眼睛操作時很難發現的問題。

結束散步的按鈕沒有名稱

散步畫面裡的結束按鈕原本只有一個

<Pressable onPress={handleFinish}>
  <Text>■</Text>
</Pressable>

正常看畫面的人可以理解這代表結束,但螢幕閱讀器可能只會把它當成一個符號。

所以補上明確的 Accessibility 資訊:

<Pressable
  accessibilityRole="button"
  accessibilityLabel="結束散步"
  onPress={handleFinish}
>
  <Text accessible={false}>■</Text>
</Pressable>

是給眼睛看的圖示,真正需要讓螢幕閱讀器知道的是「這個按鈕可以結束散步」。

暫停、繼續,以及定位還沒準備好的狀態,也一起確認了 Accessibility label 和 state。

導航箭頭不是文字資訊

導航畫面原本大概是:

↗
前方右轉
28 公尺

箭頭對視覺使用者來說很直覺,但螢幕閱讀器可能會把箭頭也讀出來。

但對使用者真正重要的是:下一步要做什麼,以及還有多遠。

所以加上 accessible={false} 把箭頭設為

<Text accessible={false}>↗</Text>

並把導航資訊整理成完整的 Accessibility label:下一步,前方右轉,剩餘 28 公尺

如果是其他狀態,就直接描述狀態 已偏離推薦路線,請返回推薦路線已抵達終點

另外把這些文案整理到 navigationAccessibility.ts,讓 UI 和 Accessibility 文案分開。

不要什麼變化都唸給使用者聽

這次還發現一個很有趣的問題。

導航距離會一直變:

28 公尺
26 公尺
24 公尺
22 公尺
20 公尺

如果每次距離變化都觸發螢幕閱讀器公告,使用者可能會一直被唸新的距離。

所以 Accessibility 並不是「資訊越多越好」。

這次把比較重要的狀態變化才設為需要主動通知,例如:

導航步驟改變
→ 通知

偏離路線
→ 通知

回到路線
→ 通知

抵達終點
→ 通知

只有距離變化
→ 不主動通知

實際上會根據 statuscurrentStepIndexmaneuver 等狀態判斷是不是值得通知。

這也是我覺得很容易忽略的一點:

不是所有資訊都需要被讀出來,真正重要的是讓使用者在正確的時間知道正確的事情。

推薦路線的選項也要知道目前選了什麼

推薦路線裡有一些可以選擇的項目,例如散步時間:

30 分鐘  45 分鐘  60 分鐘

假設目前選的是 45 分鐘,畫面上可能會用不同的背景色表示:

30 分鐘  [45 分鐘]  60 分鐘

對一般使用者來說,看顏色就知道 45 分鐘被選中了。

但 VoiceOver / TalkBack 不會知道「這個按鈕是不同顏色」,所以如果沒有額外設定,它可能只會知道這是一個「45 分鐘」的按鈕,卻不知道目前是不是選中的。

因此需要加上 accessibilityState

<Pressable
  accessibilityRole="button"
  accessibilityState={{
    selected: isSelected,
  }}
>
  <Text>45 分鐘</Text>
</Pressable>

這樣螢幕閱讀器就能知道目前這個選項是選中的。

提醒設定裡有類似的選項,也使用相同方式處理。

輸入框不能只依賴 Placeholder

推薦路線裡有開始位置、時間、距離等輸入欄位。

例如:

開始位置

[ 輸入地址或地點名稱 ]

Placeholder 可以告訴使用者「要輸入什麼」,但不一定能清楚表達這個欄位本身的名稱。

所以還需要加上 accessibilityLabel

<TextInput
  accessibilityLabel="開始位置"
/>

其他輸入欄位同樣依照用途補上 Accessibility label。

這次沒有全部改完

Accessibility 可以做的事情非常多,所以我也不是看到什麼就全部重做。

今天已經是鐵人賽最後一天,所以先把重點放在核心散步流程:

開始散步
    ↓
暫停 / 繼續
    ↓
導航
    ↓
偏離路線
    ↓
結束散步

至少確保這些最重要的操作,都能被螢幕閱讀器正確理解。

完賽啦!

回頭看這 30 天,TraceWalk 一開始其實只是一個很單純的想法:做一個散步 App。

但真的開始做之後,才發現「記錄一次散步」只是最基本的部分。

從 GPS 不準、背景定位,到路線推薦、Route Matching、導航、離線同步、Widget、統計,再到最後的 AI 分析,實際做下去才發現一個 App 還有很多原本沒有想到的問題。

這 30 天當然不可能把一個 App 做到真正完整,但至少 TraceWalk 已經從一開始的一個想法,變成了一個可以實際使用的散步 App。

到這裡 TraceWalk 的 30 天開發就正式結束了,恭喜我又一次完賽~


上一篇
優化 GPS 收到點位後的處理流程
系列文
30 天開發一款真正能每天使用的散步 App30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言