2021年 React Native のアクセシビリティを勝手に振り返る
この記事は React Native アドベントカレンダー 2021 の 6 日目の記事です。
2021 年の React Native のアクセシビリティを勝手に振り返ります。
モバイルアプリのアクセシビリティ事情
まずは、モバイルアプリ事情を勝手に振り返ります。
モバイルアプリでのスクリーンリーダー使用率が増えてきた
WebAIM では、スクリーンリーダー使用者を対象とした "Screen Reader User Survey" を大体2年ごとに実施しています。
今年度の WebAIM: Screen Reader User Survey #9 は 5 月から 6 月までに行われました。
この調査では"Mobile App vs Web Site Usage"(モバイル端末で Web とモバイルアプリどちらをよく使用するか?)という項目があるのですが、「モバイルアプリ」と回答したユーザーが 51.8% と、Web をほんの少し上回っています。
前々回の調査では 46%、前回の調査では 50.8% と、実施ごとに増加している傾向にあるようです。
また、モバイルで使用しているスクリーンリーダーの調査によれば、上位は依然として VoiceOver と TalkBack の二強ですが、中国製のスクリーンリーダーである jieshuo が台頭してきていることも見逃せません。
jieshuo は多言語、多機能でカスタマイズ可能なスクリーンリーダーです。具体的にどの国で、どのように使われているのかまでは言及されていませんが、今後の伸びに期待してます。
WCAG 3.0 のドラフトでモバイルアプリに言及
Web アクセシビリティには WCAG がありますが、モバイルアクセシビリティ自体のガイドラインは存在していません。
「WCAG 2.0 や WAI のガイドラインをモバイルに適用するためのガイドライン」は存在していますが、現代のモバイルアプリに適用するとなると、ちょっと苦しいものがあります…。
今年の 1 月には、WCAG3.0 の公開草案が出ました。評価方法などが現行の WCAG から大幅に見直されるのですが、プラットフォームも Web だけに限定されるものでなく、"mobile apps" なども含まれたガイドラインになるようです[1]。
WCAG3.0 は 2023 年に勧告される予定です。
Web Accessibility Directive でのモバイルアプリ対応が必須になった
EU 加盟国には Web Accessibility Directive という EU 指令[2]があります。
公的な団体の Web ページは、EN301 549(PDF) に基づいて、WCAG 2.1 レベル AA 相当のアクセシビリティ対応をすることが義務付けられています。
この義務が 2021 年 6 月から、モバイルアプリにも適用されるようになりました。
Web Accessibility の指令なのに、モバイルアプリの対応義務化とはこれいかに…。
React Native のアクセシビリティ事情
この 1 年、特に大きな動きはないのですが、若干ながら色々とありました。
React Native のアクセシビリティについては、先日記事を書いたので参考にしてみてください。
React Native アクセシビリティ対応をわかるための入門記事
昨年の React Native アクセシビリティ
まず、一応大きな動きがあった昨年の React Native を振り返ります。
前提として、React Native はアクセシビリティ対応があまり良くないです。
古くは「スクリーンリーダーがテキストすら素通りする」ことで苦言を呈され[3]、Airbnb も不満をもらす[4]など色々と苦労していました。
それらの時代よりは悪くないですが、良いとも言えません。
2020 年 の GAAD に、Facebook は GAAD Pledge をしました(Diamond Launches The GAAD Pledge, Announces Facebook As First Company To Take The Pledge)。
GAAD とは、"Global Accessibility Awareness Day" の略です。毎年5月の第3木曜日に世界中で実施される、アクセシビリティの啓発デーです。
GAAD Pledge については「アクセシビリティをフレームワークのコアバリューとして考えていく」という誓約だそうです。Ember.js も誓ってました[5]。
React Native アクセシビリティチームは GAAD Predge の後に、ライブラリ内でどれだけアクセシビリティ対応ができているか、テストしたようです。
React Native: Measuring the accessibility of our frameworks
そして 90 以上の アクセシビリティに関する Issue が立ちました。
それらは GitHub Project で確認できます。公開されている Issue には誰でも取り組めますが、リソース不足らしく、レビューがなかなか進まないので長期戦となります。
今年の React Native アクセシビリティ
今年の React Native におけるアクセシビリティっぽい対応を振り返ってみます。
Android の testID が正しく認識されるようになった
0.64 では、Android における testID の扱いが改善されました。
これのどこがアクセシビリティ、という話なのですが、大事な変更です。
testID は Web と同じように E2E で使用されるものですが、Android では、testId が View.tag
にセットされていました。それが、Appium[6] のドライバーである UI Automator で読み取れない問題を引き起こしました。
testID information not visible on UIAutomator in Appium. - React Native
そこで、Android で E2E テストを回す時の代替手段として accessibilityLabel
をテスト ID 代わりに使用するという、誤ったプラクティスが横行しました。
このプラクティスはポピュラーでして、個人ブログや React Native の Issue でも度々取り上げられ、見たことがあるかもしれません[7]。
testID
を accessibilityLabel
に置き換える Babel plugin も見た記憶があります。
この問題に関する PR は数年前から色々と出ていましたが、最終的には 2020 年に出た testID を resource-id と結びつける PR が採用されました。
実装もシンプルで、AccessibilityNodeInfo.setViewIdResourceName をセットするだけです。これで UIAutomator ドライバーでも testID を認識することが可能になります。
この素晴らしい PR に対して、多くの賞賛と ping がありましたが、マージされて正式版がリリースされるまでには、1 年近くかかりました…。
disabled が disabled じゃない問題の改善(Android)
今年は Good First Issue が大量に減りましたが、その中でピックアップするならこの問題です。
React Native の disabled
は、Android にとっては disabled ではありません。
Native 側は一定の条件で問答無用に true
にされるので、組み込みコンポーネントの JSX 側(つまり accessibilityState
)でなんとかするようにしていました。その組み込みコンポーネントに accessibilityState
が正しく設定されていなかったというオチです。
大量にあるコンポーネントの accessibilityState
を設定するだけなので、Issue は Good First Issue として、Umbrella 的に有志が募集されました。
Image
に至ってはわざわざ disabled
を設定できるように accessible
Props に対応するという PR も出ました[8]。
個人的には TouchableOpacity
の disabled
が反映されていなかったことに驚きました…。
それは一番必要なやつ。
React Native Accessibility Engine
思ったほど振り返るネタがなかったので、テストツールの紹介になるのですが、React Native Accessibility Engine がリリースされました。
アクセシビリティ向けのテスト関数を追加するライブラリで、まだルールはあまりないのですが、発展次第では非常に有用です。ドキュメントはもちろん知見もほぼない分野なので、Axe 的なアサーションチェックがあるのは頼りになります。
あまりにも知見がなさすぎるからか、「ベストプラクティスのサンプルアプリを公開する」というライブラリの責務でないことまでゴールに入っています…。
これからの React Native アクセシビリティ
何かしらいちゃもんつける感じにはなってしまいましたが、いくつか印象的な出来事がありました。
Respecting the Platform
2021年 8 月、React Native が、対応プラットフォームを拡大する構想を発表しました。しかし、アクセシビリティ的によくわからん一文がありました。
React Native's Many Platform Vision(React Native の公式ブログより)
最初に "Respecting the Platform" セクションがあり、その中で次のお話が出てきます。
Android users expect accessible apps using TalkBack.
訳: Android ユーザーは、TalkBack を使ってアクセスできるアプリを期待しています。
アクセシビリティにおいて "Respecting the Platform" は大事な要素の一つです。標準に乗っかればマシンリーダブルですし、不備があっても OS のアップデートで対応できるからです。
しかし、そうはならなかったライブラリが React Native です。disabled なボタンを TalkBack で実行できてしまうアプリを人々は期待していません。
「TalkBack を使ってアクセスできる」というのは、JavaScript のコードが適切にネイティブ側の API にマップされ、TalkBack に正しく認識されるデータ構造に変換されていることだと思うのですが、それがどうも現状の実装と噛み合っていません。
不安を抱きながら読んでいくと、accessibilityHint
のお話でやや違和感が。
This enabled us to build a common interface that improves how accessibility hints are handled on both mobile platforms.
日本語訳: (※アクセシビリティ対応の抽象化によって)両方のモバイルプラットフォームにおける accessibilityHint の処理を改善する共通のインターフェースを構築することができました。
Android は本来 accessibilityHint
はなく、内部的には iOS との一貫性を持たせるため「ラベル」として追加しています[9]。 "Respecting the Platform" ではなく "Respecting the React Native" です。
React Native Team には "match the expectations people have for each platform(各プラットフォームのユーザーごとの期待に応える)" という Principle もあり[10]、プラットフォームのお作法に従うことがネイティブであるなら、accessibilityHint の抽象化は少なくとも "improves" ではないように思えました。
とりあえず「アクセシビリティ意識してるんだな」ということはわかりました。
アクセシビリティモデルの見直し提案
プラットフォーム拡大に関連して necolas 氏が、あるプロポーザルを提出しています。
その内容は、React Native のアクセシビリティに関する Props や API を、可能な限り WAI-ARIA つまり Web に近づけようとするものです。
RFC: Accessibility APIs by necolas · Pull Request #410 · react-native-community/discussions-and-proposals
プロポーザルの最終的な目標は「各プラットフォームの知識を必要としない単一のアクセシビリティモデルを提供する」ことです。
具体的には、次のような内容を提案されています。
- 既存の Props の名前や値、型を変更する
-
accessibilityState
など object で渡されているフィールドを、プリミティブに渡せるよう Props に分割する - React Native for Web にある Props を移植
- 特定のプラットフォームでしか機能していない Props(
accessible
など)を削除する
現状でアクセシビリティ対応をするには、OS ごとの差異を理解する必要があります。
例えば、accessibilityLiveRegion
です。Android, Web ではフォーカス外の要素にライブリージョンを配置することは容易ですが、iOS で対応する概念はなく、AccessibilityInfo.announceForAccessibility()
でごまかす必要があります。
プラットフォームの拡大を見据えると、このようなチグハグさがネックとなってくるのでしょう。
necolas 氏は React Native for Web のメンテナーでもあり、同ライブラリでは「特定の OS に依存する Props」を排除するような変更を既に入れています。
例えば Android で View を支援技術から隠すために使う importantForAccessibility
を deprecated にしています。
このプロポーザルについての見解は割愛しますが、どこまでプラットフォーム間の互換性を保つつもりなのかが気になっています。全てが Web と同じわけではありません。例えば Web や Android にはないですが iOS にとっては必要な accessibilityHint
なども存在します。
それらの機能を削除したり、あるいは他 OS との差異を合わせるオレオレ実装をすることは "Respecting the Platform" の思想から余計遠ざかるので、更なる議論が必要に思えます。
終わり
今年のペースを鑑みるに、来年の React Native も何かありそうでないかもしれないですが、少しずつアクセシブルになっていくのを期待してます。
-
名称も Web Content Accessibility Guidelines から W3C Accessibility Guidelines に変更されました。 ↩︎
-
EU 指令とは、EU 加盟各国に対して、国内での立法を義務付ける法令です。 ↩︎
-
Accessibility / 508 compliance ? - GitHub https://github.com/facebook/react-native/issues/342 ↩︎
-
React Native at Airbnb: The Technology https://medium.com/airbnb-engineering/react-native-at-airbnb-the-technology-dafd0b43838 ↩︎
-
The Ember JS Framework Takes the GAAD Pledge https://blog.emberjs.com/gaad-2021 ↩︎
-
モバイルアプリ向けのブラックボックス E2E フレームワークです。 https://appium.io/ ↩︎
-
Espresso ドライバーを使用するという回避策はありました。Automating React Native apps | CodeceptJS https://codecept.io/mobile-react-native-locators.html ↩︎
-
[Accessibility] Fix Image does not announce "disabled" https://github.com/facebook/react-native/pull/31252 ↩︎
-
Accessibility API Updates - React Native Blog https://reactnative.dev/blog/2018/08/13/react-native-accessibility-updates#solution-two-adding-accessibility-hints ↩︎
-
React Native Team Principles - React Native Blog https://reactnative.dev/blog/2020/07/17/react-native-principles#native-experience ↩︎
Discussion