1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AIにコードを書かせて浮いた時間、アクセシビリティに回してもいいんじゃないか

1
Last updated at Posted at 2026-08-19

そういえば、という話

AIにコードを書かせるようになって、実装にかかる時間はそれなりに減った。
その分で機能をもう1個進める、というのが普通の使い方だと思うけれど、
そういえば、と思ったことがある。

アクセシビリティ対応って、今までずっと
「やったほうがいいのは分かっているけど手が回らない」で流してきた。
でも手が回らなかった理由のほうが先に解消されつつあるのでは、という思いつきです。

しかもこれ、お客さんに公開するものなら、
機能をもう1個増やすより効く場面もあるはず。

以下は、実際にやるとしたらどこから手をつけるか、を整理したものです。

前提:サイトの性質によって、かける労力は変わる

最初に立場をはっきりさせておくと、
すべてのプロダクトで同じだけ対応すべき、とは思っていない。

優先度が上がりやすいのは、こういうもの。

  • 公共性が高いもの(自治体、医療、金融、教育)
  • 不特定多数が入口として使うもの(EC、予約、問い合わせフォーム)
  • 代替手段がないもの。「電話でも申し込めます」がないなら、その画面が唯一の窓口になる
  • BtoBで、相手方の調達要件にアクセシビリティが入っているもの

逆に、利用者が全員把握できている社内ツールなら、
そこまで踏み込まないのも妥当な判断だと思う。

ただ、そういうケースでも「ゼロか全部か」ではなくて、
コストが安いところだけ拾うという選択肢はある。この記事で扱うのはそこです。

なぜ今まで後回しになっていたか

思い返すと、理由は2つに整理できる。

ひとつめは知識のコスト。
aria-* をどう使うのが正しいのか、role を足すべきなのか、
毎回調べ直していて、チーム全員が同じ精度で判断できる状態ではなかった。

ふたつめは検証のコスト。
キーボードだけで全画面を触り直す、コントラスト比を測る、といった作業は、
一度やっても機能追加のたびに崩れるので、継続的にやらないと意味がない。

この2つは、AIが比較的埋めやすい。
アクセシビリティ対応の多くは創造的な作業ではなく、
既知のルールを漏れなく適用する作業に近いからです。

安いところから順に

1. クリッカブルな div を button にする

たぶん一番件数が多くて、一番効くのがこれ。

修正前:

<div className="card" onClick={() => onSelect(item.id)}>
  {item.name}
</div>

修正後:

<button type="button" className="card" onClick={() => onSelect(item.id)}>
  {item.name}
</button>

div のままだと、Tabキーで到達できず、Enterでも反応せず、
スクリーンリーダーは「ボタン」だと読み上げない。
button にするだけでこの3つが同時に解決する。

div のまま対応しようとすると tabIndex={0}role="button"
EnterとSpaceそれぞれの onKeyDown を自前で書くことになるので、
要素を変えられるなら変えたほうが早いし壊れにくい。

なお、button はブラウザ既定のスタイルが載るので、
既存の見た目を維持するには appearance: nonebackground: none
font: inherit あたりのリセットが必要になる。ここだけは手間が増える。

divとbuttonでTabキーの到達順を比較した図。divではカード3枚が飛ばされ、buttonでは1枚ずつ到達できる

2. モーダルのキーボード操作

マウスで使っているぶんには誰も気づかないが、
モーダルを開いてTabを押し続けると背後のリンクにフォーカスが移っていく、
というのはよくある。見るべきは2点で、

  • Escapeキーで閉じる
  • 開いている間、フォーカスがモーダルの外に出ないようにする(フォーカストラップ)

フォーカストラップは自前で書くと地味に間違えるので、
ライブラリに寄せるか、<dialog> 要素の showModal() を使うのが確実です。
showModal() はフォーカストラップとEscapeでのクローズをブラウザ側でやってくれる。

閉じたあとに、開く前のボタンへフォーカスを戻すところまでやると、
キーボードだけで使ったときの体感がかなり変わる。

3. エラーを色だけで伝えない

バリデーションエラーを入力欄の赤い枠線だけで表現しているケース。
これだと、色の見分けがつきにくい人には何も伝わらないし、
スクリーンリーダーにも枠線の色は読み上げられない。

こう変える:

<label htmlFor="email">メールアドレス</label>
<input
  id="email"
  aria-invalid={!!error}
  aria-describedby={error ? "email-error" : undefined}
/>
{error && <p id="email-error">{error}</p>}

テキストでエラー内容を出したうえで、aria-describedby で入力欄と紐付ける。
labelinputhtmlFor / id で結ぶのも同時にやっておく
(ここが切れていると、スクリーンリーダーが「編集テキスト」としか読まない)。

4. コントラスト比

補助テキストの薄いグレーが、だいたい落ちる。

WCAG 2.1 の達成基準 1.4.3(レベルAA)は、通常サイズの文字で 4.5:1 以上。
白背景に #999999 だと約 2.85:1 で足りず、#767676 まで落とせば約 4.54:1 で満たす。

目新しい話ではないけれど、ここを挙げたのは修正コストが一番安いから。
個別のクラスを直すのではなく、デザイントークンの値を1つ差し替えれば全画面に効く。
ライトとダークでテーマを分けているなら、両方で測る必要があるのだけ注意。

文字色 #999999 と #767676 のコントラスト比を白背景で比較した図。前者は2.85:1でAA未達、後者は4.54:1でAA達成

5. lintとCIに載せて、戻らないようにする

一度直しても、機能追加のたびに同じパターンが戻ってくる。
なので eslint-plugin-jsx-a11y を入れて、
div にクリックハンドラを付けた場合や、label と入力欄が結ばれていない場合に
CIで落ちるようにしておく。

ただ、既存コードに対して有効にすると指摘が大量に出るので、
いきなり全部エラーにすると誰も直せない。
まずこれ以上増やさない状態を作るほうが先だと思う。

ESLint自体は「新規のコードか既存のコードか」を区別しないので、
そこは運用側で分ける必要がある。やり方はいくつかあって、

  • 差分に対してだけ実行する(lint-staged や、CIで変更ファイルだけを対象にする)
  • --max-warnings で警告の総数に上限を設け、増えたら落とす
  • ルールを warn で入れておき、既存分を潰しながら順次 error に上げる

どれでもいいけれど、「既存の指摘は残っていても、新しく増えたら落ちる」
という状態にしておくと導入しやすい。

AIに直させるのは一度でいいけれど、
戻らない仕組みだけは人間側で残しておく必要がある。

AIへの投げ方

「アクセシビリティを改善して」だと、範囲が広すぎて出力が安定しない。

具体的なルールを1つずつ指定したほうがいい。たとえば

このディレクトリ配下で、onClickを持つdiv/spanを列挙して。
それぞれbuttonかaに置き換えられるか判断して、
置き換えられないものは理由を書いて。

のように、判断基準を渡して、例外は理由付きで返させる形にすると、
機械的に全部 button にされて壊れる、という事故を避けやすい。

一方で、aria-live をどこに置くべきか、
このUIに role を足すべきかどうか、といった設計寄りの判断は、
AIの出力がそれらしく見えても間違っていることがある。
ここは仕様を自分で確認したほうが早い。

ここから先は自動化できない

自動チェックで拾えるのは、機械的に判定できるルールだけです。

  • alt 属性が「ある」ことは検出できるが、その説明文が適切かは判定できない
  • フォーカス順序が「DOM順」であることは分かるが、それが自然な順序かは分からない
  • コントラスト比は測れるが、画像の上に載った文字は測れない

結局、最後はキーボードだけで一周してみるしかない。
ただ、その一周にたどり着くまでの機械的な修正をAIに潰してもらえるなら、
かかる時間はかなり違ってくるはずで、そこが今までとの差分だと思っている。

まとめ

  • AIで実装が速くなった分は、機能追加だけでなく、後回しにしていた品質に回せる
  • アクセシビリティ対応は「既知のルールの適用」が大半なので、AIと相性がいい
  • ただし設計判断が絡む部分は、AIの出力を鵜呑みにせず自分で確認する
  • 一度直すだけでは戻るので、lintとCIに載せるところまでやる
  • サイトの性質によってかける労力は変わるが、「安いところだけ拾う」判断はどこでも取れる

全部やろうとすると腰が重いので、まずマウスから手を離して、
自分の担当画面をTabキーだけで一周してみるのがいいと思います。
これ自体は数分で終わるし、直すべき箇所がそこで具体的になる。
そこまで来れば、あとは今回挙げたような機械的な修正が大半です。

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?