はじめに
「このボタン、スクリーンリーダーで読み上げられない」——E2Eテストでも、パフォーマンステストでもない。そういう問題が、コミット前に自動で検知されてWCAG準拠に修正される仕組みをClaude Codeで作る話だ。
機能開発・パフォーマンス・セキュリティが優先される中、アクセシビリティは「後でやる」扱いになりがちだ。しかし毎年数千件のADA関連訴訟が米国で提起されているという現実(UsablenetやEcomBack等の業界調査)を見ると、「できれば対応」では済まない局面も増えている。さらに欧州でもEAA(European Accessibility Act)が2025年に施行され、グローバル展開するプロダクトにとってWCAG準拠はリーガルリスクの問題でもある。
問題の本質は「後から直す」コストにある。設計段階で検知すれば30分の修正が、リリース後では数日のリファクタリングになる。axe-core・eslint-plugin-jsx-a11y・Playwrightを組み合わせたa11yの自動化により、「後から監査」から「実装と同時に準拠」へのシフトが可能になる。
CLAUDE.mdでa11yポリシーを定義する——「最初から準拠」の設計
アクセシビリティ品質を底上げする最初のステップは、CLAUDE.mdにWCAGルールを定義することだ。Claude Codeがコンポーネントを生成するとき、CLAUDE.mdに書かれたルールが判断基準になる。「alt属性を忘れないでください」と毎回プロンプトに書くのではなく、一度ポリシーを定義すれば以降は自動的に従う。
# CLAUDE.md(アクセシビリティポリシー)
## Accessibility Requirements
### WCAG準拠レベル
- 目標: WCAG 2.1 Level AA準拠
- 全UIコンポーネントに適用
- 新規コンポーネントはリリース前にaxe-coreスキャンを必須とする
### 必須ルール
- 全img要素にalt属性(装飾画像はalt="")
- インタラクティブ要素にaria-labelまたはテキストラベル
- フォームの全入力にラベル関連付け(<label>またはaria-labelledby)
- 見出しは飛び番禁止(h1→h2→h3の順序を守る)
- キーボードフォーカスは全インタラクティブ要素に届くこと
- 色コントラスト比: 通常テキスト4.5:1以上、大テキスト3:1以上
### 禁止パターン
- aria-hidden="true" をフォーカス可能な要素に付与
- tabindexに正の値を使う(tabindex="-1"は可)
- role="button" を<div>に付与(<button>を使うこと)
- カラーのみで状態を表現(色盲ユーザーへの配慮)CLAUDE.mdにこれを定義しておくと、Claude Codeが新しいフォームコンポーネントを実装するとき、labelの関連付けやaria属性を自動で付与するようになる。「準拠を覚えさせる」ではなく「準拠がデフォルト状態になる」という違いが重要だ。
興味深いのは、axe-core自体がCLAUDE.mdを持っていることだ(dequelabs/axe-core)。accessibility testingの主要OSSライブラリが、Claude Codeでの開発にCLAUDE.mdを活用している。テストパターンやAPIの使い方がCLAUDE.mdに定義されており、「ライブラリ開発者がClaude Codeをどう使うか」の実例として参考になる。
3層のa11y自動化——静的解析・ブラウザテスト・E2E統合
アクセシビリティの自動テストは、速度と検知精度のトレードオフで設計する必要がある。全テストを全PRで実行するとCIが重くなり、何も実行しないと問題が積み重なる。実用的な解は「3層アーキテクチャ」だ。
| 層 | ツール | タイミング | 速度 |
|---|---|---|---|
| **静的解析層** | eslint-plugin-jsx-a11y | ビルド時・エディタ | 高速(ミリ秒) |
| **ブラウザ実行層** | axe-core(レンダリング済みDOM) | ランタイムテスト | 中速(秒) |
| **E2E統合層** | Playwright + axe-core | CIパイプライン | 低速(分) |
静的解析層では、eslint-plugin-jsx-a11yがJSXコードを構文解析してa11y違反を検知する。エディタ上でリアルタイムに赤線が引かれるため、書いた瞬間に問題がわかる。とタイプした直後に「alt属性がない」と警告が出る体験は、レビューサイクルを待つことなく問題を解消できる。
ブラウザ実行層では、axe-coreが実際にレンダリングされたDOMを解析する。静的解析では検知できない問題——コントラスト比の実際値・動的に追加されるARIAラベルの正確さ・フォーカス順序——がここで明らかになる。
E2E統合層では、PlaywrightとaxeをCIで組み合わせる。
// playwright.config.ts でのaxe統合
import { checkA11y } from 'axe-playwright';
test('チェックアウトページのアクセシビリティ', async ({ page }) => {
await page.goto('/checkout');
await checkA11y(page, null, {
axeOptions: {
runOnly: {
type: 'tag',
values: ['wcag2a', 'wcag2aa', 'wcag21aa'],
},
},
});
});Playwright MCPのa11yツリー活用はさらに踏み込んだアプローチだ。Playwright MCPは通常のDOMではなく、アクセシビリティツリーをベースにUIと対話する(builder.io)。これはスクリーンリーダーが実際に読み取るツリーと同じ構造であり、Claude Codeがスクリーンリーダーの視点でUIを評価できることを意味する。
通常のテスト: DOM要素 → CSSセレクタ → クリック
Playwright MCP: a11y tree → role/name → インタラクション「button[data-cy='submit']をクリック」ではなく「role=button name='注文を確定する'をクリック」という操作になる。テストコードが視覚的な実装ではなく意味的な構造に依存するため、コンポーネントのCSSクラスやHTMLの構造が変わってもテストが壊れにくい。
ARIAラベルの自動生成はClaude Codeが得意とする領域だ。コンポーネントの用途からaria-labelの内容を推測し、デザインシステム全体に一貫したARIA命名を適用できる。を
GitHubにはclaude-a11y-skill(airowe)やskill-a11y-audit(snapsynapse)といったコミュニティスキルも存在する(いずれもGitHubで実在確認済み)。前述の3層アーキテクチャを一つのスキルコマンドにまとめたものとして参考になる。
a11y自動化の限界を理解しておくことも重要だ。axe-coreが自動検知できるのは全WCAGルールの30〜40%程度にとどまる(Deque公式見解)。認知負荷・コンテキストの適切さ・複雑なARIAパターンは人間によるレビューが必要だ。「自動化で100%準拠できる」という期待は持たないこと——ツールは問題の早期発見を助けるが、スクリーンリーダーユーザーによる実際のテストは欠かせない。
GitHub Actions × a11yスキャン——CIパイプラインへの組み込み方
CI設計の肝は「何をいつ実行するか」の判断だ。全テストを全PRで実行するとCIが重くなり、何も実行しないと問題が蓄積する。コンポーネント変更時のみa11yスキャンを走らせるpathsフィルタが実用的な解になる。
# .github/workflows/a11y-check.yml
name: Accessibility Check
on:
pull_request:
paths:
- 'src/components/**' # コンポーネント変更時のみ実行
jobs:
a11y-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup and start dev server
run: |
npm ci
npm run build
npx serve dist &
sleep 3
- name: Run axe-core CLI
run: |
npx @axe-core/cli http://localhost:3000 \
--tags wcag2a,wcag2aa,wcag21aa \
--reporter json \
--exit
- name: Lighthouse a11y audit
uses: treosh/lighthouse-ci-action@v12
with:
urls: |
http://localhost:3000
budgetPath: .lighthouserc.jsonLighthouseのアクセシビリティスコアをパス条件にする設定も加えると、スコアが閾値を下回るPRがマージできなくなる。
{
"ci": {
"assert": {
"assertions": {
"categories:accessibility": ["error", {"minScore": 0.9}]
}
}
}
}3層トリガー戦略で効率と品質を両立する。
- 全PRで静的解析を実行: eslint-plugin-jsx-a11yは数ミリ秒で終わるため、全PRで実行してもCIコストはほぼゼロ
- コンポーネントPR時のみブラウザテスト: axe-coreはpaths: ['src/components/**']でコンポーネント変更時のみ実行
- 週次で全ページスキャン: 定期スケジュールでLighthouse + axe-coreの全ページ監査を行い、蓄積した問題を検知する
この設計をCLAUDE.mdに記載しておくと、CI設定をClaude Codeに生成させるときに適切なトリガー戦略を自動で選択するようになる。
Accessibility Agentsと呼ばれるマルチエージェント設計(i18n/RTL・データ可視化・フォーム・スクリーンリーダー対応を専門エージェントが分担)も登場しているが、メンテナンス状態を確認中のためここでは概念的な紹介にとどめる。
まとめ
起点はCLAUDE.mdへのWCAG 2.1 AA準拠ルール定義だ。そこを整えたら、静的解析(eslint-plugin-jsx-a11y)→ブラウザテスト(axe-core)→E2E統合(Playwright)の3層アーキテクチャをGitHub Actionsに組み込む。全PRで静的解析・コンポーネントPR時のみブラウザテスト・週次全スキャンという3層トリガー戦略が揃えば、a11y負債が蓄積しない状態が作れる。
重要なのは「自動化は入口に過ぎない」という認識だ。axe-coreで検知できるのはWCAG違反の30〜40%。残りの60〜70%は人間のレビューとスクリーンリーダーユーザーによる実際のテストが必要になる。ツールは問題の早期発見と修正コストの削減を助けるが、アクセシビリティの本質は「実際に使えるかどうか」にある。
Claude Codeを使ったa11y自動化の出発点として、まずCLAUDE.mdに5行のルール定義から始めてみてほしい。その5行が、チーム全体の「デフォルトがWCAG準拠」という状態を作る第一歩になる。

コメント