テスト・検証

a11y は「自動テストで全部見つかる」ものではない。 自動チェックは入口にすぎず、本当の品質は手動 + 実機 + ユーザーテストで決まる。とはいえ 自動で見える3〜4割を逃すのもったいないので、多層に組むのが定番。

自動テストでは見つかる/見つからないもの

自動で見つかる(〜30%)

自動では見つからない(70%超)

1. ブラウザ拡張で素早くスキャン

axe DevTools(Chrome / Firefox / Edge)

業界標準。誤検知が極めて少ないのが信頼される理由。 DevTools に新しいタブが追加され、ページをスキャンしてルール違反を一覧表示。

Lighthouse

Chrome に組み込み。Performance / Accessibility / SEO / Best Practices を計測。 Accessibility スコアを見て、100 でないなら必ず内容を確認。 ただし axe-core を内部で使っているので、深い検査には axe DevTools の方が向いている。

WAVE(WebAIM)

Web 上で URL を入れるか、ブラウザ拡張で。視覚的にエラー位置をハイライトするのが特徴。 コントラスト確認やランドマーク表示も便利。

2. CI / E2E に組み込む

jsx-a11y(ESLint)

React コードのレビュー時点で怪しい JSX を弾く<img> に alt がない、ボタンに onClick だけ付いて role がない、等を検出。

npm install -D eslint-plugin-jsx-a11y
// eslint.config.js
export default [
  {
    plugins: { "jsx-a11y": jsxA11y },
    rules: {
      "jsx-a11y/alt-text": "error",
      "jsx-a11y/anchor-is-valid": "error",
      "jsx-a11y/click-events-have-key-events": "warn",
      // ...
    },
  },
]

jest-axe / vitest-axe

単体テストレベルでレンダリングしたコンポーネントを axe にかける

import { axe, toHaveNoViolations } from "jest-axe"
import { render } from "@testing-library/react"

expect.extend(toHaveNoViolations)

it("Button has no a11y violations", async () => {
  const { container } = render(<Button>送信</Button>)
  expect(await axe(container)).toHaveNoViolations()
})

Playwright / Cypress + axe

E2E で実際にレンダリングされたページに axe をかける。動的な state(モーダル開いた後など)も テストできる。

// Playwright
import AxeBuilder from "@axe-core/playwright"

test("home is accessible", async ({ page }) => {
  await page.goto("/")
  const results = await new AxeBuilder({ page }).analyze()
  expect(results.violations).toEqual([])
})

pa11y / pa11y-ci

CLI でサイト全体をクロールしてスキャン。CI に組み込みやすい。

3. ブラウザ DevTools の活用

Chrome DevTools — Accessibility パネル

Elements パネル → 右側のタブから Accessibility。 選択中の要素について Name / Role / Stateアクセシビリティツリーを表示。

「自分が思っていた通りに支援技術に見えているか」を即座に確認できる。

Rendering タブ

Coverage タブ で「使ってない CSS」を発見

a11y 直接の話ではないが、未使用 CSS で古い hover スタイルが残っていてフォーカス時に変な見た目になる類のバグを発見しやすい。

4. 手動チェックリスト

キーボードだけで操作(5分)

  1. マウスから手を離す
  2. Tab で全部の操作要素に到達
  3. 各要素でフォーカスが見える
  4. Enter / Space で動作
  5. モーダル / メニュー: Esc で閉じてフォーカスが戻る
  6. 循環するメニューで「逃げ場」がない事態にならない

200% / 400% ズーム(2分)

  1. ブラウザのズーム 200% で操作可能か
  2. 320px 幅にして横スクロールが出ないか
  3. UI が重なって読めなくならないか

色覚シミュレーション(1分)

  1. Chrome DevTools の Rendering タブから視覚特性をシミュレート
  2. 赤緑色弱で「色だけ」の手がかりが残っていないか
  3. グラフの凡例・状態表示・必須項目の印

スクリーンリーダで主要フローを通す(10〜30分)

  1. VoiceOver / NVDA を ON
  2. ホームから主要な目的(記事を読む / 商品を買う / 投稿する)まで完走できるか
  3. 各ステップで「何の要素か」「次は何をすべきか」が伝わるか
  4. エラーや状態変化が通知されるか

prefers-reduced-motion ON での動作(1分)

  1. OS の「動きを減らす」を ON、または DevTools でエミュレート
  2. 派手なアニメ・パララックスが弱まっているか / 止まっているか
  3. 必要なフィードバック(state 切替の即時反映)は残っているか

5. 実機・実ユーザーテスト

最も価値が高いがコストもかかる。可能なら定期的に実施する:

テストを「いつ」やるか

タイミングやること
デザイン段階カラートークンのコントラスト確認、UI パターンの選定
実装中ESLint (jsx-a11y)、ブラウザで都度キーボード確認
PR レビュー軽くキーボードで触る、新規 UI に対する SR チェック
CIjest-axe / playwright-axe で自動チェック
リリース前主要ページの手動チェックリスト全項目
定期四半期に1回程度の網羅監査、実ユーザーテスト

改善のステップ(小さく始める)

  1. カラーパレットを a11y 準拠に直す — 全ページに効く一発投資
  2. フォーカスインジケータを CSS で整える:focus-visible で全体に適用
  3. html lang を入れる — 単純だが見落としがち
  4. スキップリンクを追加
  5. 主要フローのフォームに label を整える
  6. SPA ならルート遷移時のフォーカス管理を入れる
  7. 派手なアニメに prefers-reduced-motion
  8. カスタム UI(モーダル、メニュー、タブ)を APG 準拠 / ライブラリで書き直す
  9. 定期的な手動チェック / 実機テスト

参考リソース

完璧主義より継続主義

a11y は「100点取ってからリリース」するものではなく、「劣化させずに、徐々に改善」するもの。
最初は AA を主要フローでクリアし、CI に jest-axe を入れて悪化を防ぐのが現実的なスタートライン。