英語学習アプリの下の段のタブを、見た目を1画素も変えずにキーボードと読み上げで操作できるようにした記録

やりたかったこと:見た目を変えずに、キーボードと読み上げで使えるようにする

英語学習アプリ Words Admin(https://words-admin.web.app/)の画面の下の段には、AI-Phrase・AI-Memo・More などのタブが並んでいます。このタブは、キーボードだけで操作したときや画面の読み上げを使ったときに、ほとんど使えない状態でした。

作業の前に、次の4つを条件として決めました。

  • 見た目は変えない
  • 失敗を確かめるテスト(負のテスト)を付ける
  • ローカルで確かめてから本番で確かめる
  • 主要な導線の定期検査 25/25 を保つ

「見た目は変えない」は、言うだけで済ませずに、測って確かめる対象にしました。

何が壊れていたか

下の段は、見た目はタブでした。しかし中身は「クリックしたときの処理」だけを持つ <div> で、次の3つの問題がありました。

  • 役割(role)も名前も無い。 キーボードの Tab で一度も止まらない。画面の読み上げでは「何か」としか分からない。
  • 中にある飾りのアイコンボタンだけが焦点を受け取る。 押しても何も起きない行き止まりになっていた。
  • 今どのタブにいるかが色だけで示されている。 意味としては出ていなかった。

見つけたきっかけは別の試験です。役割で探す書き方では、タブが見つかりませんでした。最初は試験の道具の誤りとして片付けかけました。しかし「役割も名前も無い」ことは、そのまま「キーボードと読み上げでは操作できない」ことを意味していました。道具の誤りではなく、本物の問題だったわけです。

どう直したか

直した内容は次の表のとおりです。

対象 直し方
各タブ role="button"/tabIndex=0/aria-label/今いるタブに aria-current="page"/Enter と Space で移動
Space 既定の動作を止める(止めないと、押したのに画面だけ下に送られる)
More(メニューを開くタブ) aria-haspopup="dialog"/開いているかを aria-expanded で示す
飾りのアイコン tabIndex={-1} と aria-hidden(焦点と読み上げから外す)
入れ物 <nav aria-label>(画面の中の「ナビゲーション」として読み上げで飛べる)
焦点の輪 :focus-visible のときだけ=マウスで押しても輪は出ない

表のとおり、Space は既定の動作を止めないと、押したのに画面だけが下に送られます。飾りのアイコンは tabIndex={-1} と aria-hidden を付けて、焦点と読み上げの両方から外しました。前は焦点を受け取るのがこのアイコンだけで、押しても何も起きない行き止まりだったためです。

焦点の輪は :focus-visible のときだけ出します。マウスで押しても輪は出ません。

「見た目は変えない」を画素で測った

直す前の本番と直した後のローカルで、下の段の 64px を幅 390px で撮り、画素ごとに比べました。

結果は 異なる画素 0 / 24,960 です。

「見た目は変えない」を言うだけで終わらせないために撮りました。

テストは「直しを外したら落ちるか」まで確かめた

負のテストは12件で、そのうち5件が失敗を確かめるものです。

  • 名前の無い焦点が下の段に残っていない(飾りが焦点を取り返すと落ちる)
  • 飾りのアイコンは焦点を受け取らず、読み上げにも出ない
  • Enter と Space 以外のキーでは移動しない
  • Space の既定の動作(画面送り)を止めている
  • Enter を押しても、押していないタブへは移動しない

テストが効いているかを見るため、直しを外して実測しました。結果は12件中 11件が落ちる でした。

通ったまま残った1件は「Enter と Space 以外では移動しない」です。壊れた状態では何も動かないので、このテストは通ります。これは「反応しすぎ」を見張るテストなので、それで正しい結果です。

作る途中で直したこともあります。最初の版では、直しを外すと全部が同じ1つの理由(入れ物が無い)で落ちていました。これでは何が壊れたのか分かりません。そこで、検査ごとに別々の理由で落ちるように作り直しました。

通しの試験にキーボードだけの段を足した

画面を通しで確かめる試験に、キーボードだけの段を足しました。マウスを使わず、Tab だけで下の段の AI-Memo に焦点を運びます。そこで Enter を押して一覧を開き、登録が1件以上あることを確かめます。

実測では Tab 8回で到達・役割は button・登録数 5 でした。

実測

結果
ローカル 16/16・詰まり 0
本番 16/16・詰まり 0
主要な導線の定期検査 25/25
単体テスト 148 passed(このタブの12件を含む)
下の段の見た目 異なる画素 0 / 24,960

最初に決めた順番どおり、ローカルで確かめてから本番で確かめました。主要な導線の定期検査は 25/25 を保っています。

業務に置き換えると(社内ツール・業務画面のアクセシビリティ対応)

今回は英語学習アプリでの記録ですが、社内ツールや業務画面のアクセシビリティ対応にも同じ考え方が使えます。

  • 「見た目を変えない」は、画素の比較で確かめられる。 変える前と変えた後を同じ幅で撮って比べれば、数字で残せます。
  • テストは「直しを外したら落ちるか」まで確かめる。 外しても通るテストは何も守っていません。ただし「反応しすぎ」を見張るテストのように、壊れた状態で通るのが正しいものもあります。
  • テストは、検査ごとに別々の理由で落ちるように作る。 全部が同じ1つの理由で落ちると、何が壊れたのか分かりません。
  • 対応の範囲を、役割・名前・焦点・キー操作・現在地の5つに分けて点検すると漏れにくい。
  • 役割で探して見つからないときは、道具の誤りと決めつけない。 今回は、それが「キーボードと読み上げでは操作できない」という本物の問題でした。

この記事は、TechAthletes が自社のサービスを作る中で記録した実測をもとに書いています。業務への導入のご相談は 仕事の窓口 で受け付けています。

✨ Claudeエージェントを複数走らせるならAgent Desk
Terminal tile manager for macOS。全ソース付き $10 買切り。
Agent Desk を見る →

投稿者 TechAthletes 編集部

TechAthletes は、AI・クラウド・開発ツールの技術記事を公開しているメディアです。記事内の商品リンクには広告(アフィリエイトリンク)が含まれます。

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です

Click to listen highlighted text!