Claude CodeでWebアクセシビリティを自動化する実践ガイド|axe-core・Pa11y CI・WCAG 2.2 AA準拠

Claude CodeでWebアクセシビリティを自動化する実践ガイド|axe-core・Pa11y CI・WCAG 2.2 AA準拠 AI開発

Webアクセシビリティは「対応したほうがいい」から「対応しなければならない」へと変わりつつあります。2024年4月の障害者差別解消法改正で民間企業にも合理的配慮の提供が義務化され、EUではEuropean Accessibility Act(EAA)が2025年6月に施行されました。

Claude Codeを使うと、アクセシビリティ対応を開発ワークフローに組み込むことができます。axe-coreによる自動テスト、eslint-plugin-jsx-a11yによる静的解析、Pa11y CIによるCI/CD統合——これらをCLAUDE.mdに設定しておけば、Claude Codeが生成するコードが最初からWCAG 2.2 AA準拠になります。この記事では、その具体的な方法を解説します。

スポンサーリンク

WCAG 2.2の概要 ── 何を満たせばよいのか

WCAG(Web Content Accessibility Guidelines)2.2は2023年10月にW3C勧告となった最新のアクセシビリティ基準です。実務ではAA準拠が目標になります。

WCAG 2.2で追加された主なAA基準は以下の4つです。

基準 レベル 内容
2.4.11 Focus Not Obscured AA キーボードフォーカスを受けた要素が完全に隠れてはいけない
2.5.7 Dragging Movements AA ドラッグ操作にはシングルポインタの代替手段が必要
2.5.8 Target Size (Minimum) AA タッチターゲットは最小24×24 CSSピクセル
3.3.8 Accessible Authentication AA 認証で認知機能テスト(CAPTCHA等)を要求しない
日本の法制度:2024年4月の障害者差別解消法改正により、民間事業者にも合理的配慮の提供が義務化されました。Webアクセシビリティ自体は「環境の整備」として努力義務ですが、障害のある利用者からの申し出に対して「負担が重すぎない範囲」での対応は法的義務です。事前にWCAG準拠しておくことが最善の防御策です。

CLAUDE.mdにアクセシビリティルールを記述する

Claude Codeにアクセシビリティ意識を「常に」持たせるには、CLAUDE.mdにルールを明記します。

CLAUDE.md(アクセシビリティルール)
## アクセシビリティ基準(WCAG 2.2 AA準拠)

### 必須ルール
- すべての画像にalt属性を付与(装飾画像はalt="")
- インタラクティブ要素にはaria-labelまたはvisible labelを必須
- 色コントラスト比: 通常テキスト4.5:1以上、大テキスト(18px+ bold/24px+)3:1以上
- キーボード操作: すべての機能がキーボードのみで操作可能
- フォーカスインジケータ: カスタムスタイル時も視認可能に(outline: none禁止)
- タッチターゲット: 最小24x24 CSSピクセル(WCAG 2.5.8)
- フォームエラー: aria-describedbyでエラーメッセージをプログラム的に関連付け
- 見出し階層: h1→h2→h3の順で飛ばさない
- ランドマーク: main, nav, header, footer を適切に使用

### 自動チェックツール
- ESLint: eslint-plugin-jsx-a11y(strictモード)
- テスト: @axe-core/playwright でE2Eテスト時にa11yチェック
- Storybook: addon-a11yでコンポーネント単位チェック
- CI: Pa11y CIでPR時に自動チェック

### 禁止パターン
- div/spanにonClick付与(button要素を使用すること)
- autofocusの無秩序な使用
- aria-hiddenをフォーカス可能な要素に付与
- tabindex > 0 の使用
- CSSのoutline: noneでフォーカスインジケータ削除
CLAUDE.mdに書いておくだけで、Claude Codeが新しいコンポーネントを生成するたびに、aria属性・alt属性・キーボード操作・コントラスト比を自動的に考慮したコードを出力します。

eslint-plugin-jsx-a11yで静的解析する

コーディング時点でアクセシビリティ違反を検出する最も効率的な方法は、ESLintの静的解析です。

eslint-plugin-jsx-a11yの設定プロンプト
eslint-plugin-jsx-a11y をstrictモードで導入してください。

要件:
- Flat Config(eslint.config.js)形式
- strictプリセット(recommendedより厳格)
- 以下を error に設定:
  - alt-text, aria-props, aria-role, click-events-have-key-events,
    heading-has-content, label-has-associated-control
- 設定後に全ファイルでlintを実行してエラー一覧を出してください
eslint.config.js(Claude Codeが生成)
import jsxA11y from "eslint-plugin-jsx-a11y";

export default [
  // ... other config
  {
    plugins: { "jsx-a11y": jsxA11y },
    rules: {
      ...jsxA11y.flatConfigs.strict.rules,
      // 追加で厳格にする項目
      "jsx-a11y/alt-text": "error",
      "jsx-a11y/click-events-have-key-events": "error",
      "jsx-a11y/no-noninteractive-element-interactions": "error",
      "jsx-a11y/label-has-associated-control": ["error", {
        controlComponents: ["Input", "Select", "Textarea"],
      }],
    },
  },
];

axe-core + Playwrightでアクセシビリティを自動テストする

@axe-core/playwrightを使うと、E2EテストにWCAGチェックを組み込めます。ページ遷移のたびにアクセシビリティ違反を自動検出します。

axe-core + Playwrightのセットアップ
npm install --save-dev @axe-core/playwright
アクセシビリティテスト(Playwright)
import { test, expect } from "@playwright/test";
import AxeBuilder from "@axe-core/playwright";

test.describe("アクセシビリティ", () => {
  test("トップページがWCAG 2.2 AA準拠", async ({ page }) => {
    await page.goto("/");
    const results = await new AxeBuilder({ page })
      .withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa", "wcag22aa"])
      .analyze();
    expect(results.violations).toEqual([]);
  });

  test("フォームページがWCAG 2.2 AA準拠", async ({ page }) => {
    await page.goto("/contact");
    const results = await new AxeBuilder({ page })
      .withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa", "wcag22aa"])
      .exclude("#third-party-widget") // サードパーティ部分は除外
      .analyze();
    expect(results.violations).toEqual([]);
  });
});
axe-coreはWCAG違反の約57%を自動検出できます。残りは手動テスト(スクリーンリーダーでの確認、キーボード操作テスト等)が必要です。自動テストは「最低限の品質ゲート」として位置づけてください。

Pa11y CIでCI/CDにアクセシビリティゲートを設置する

.pa11yci(設定ファイル)
{
  "defaults": {
    "standard": "WCAG2AA",
    "runners": ["axe"],
    "timeout": 10000,
    "viewport": { "width": 1280, "height": 1024 }
  },
  "urls": [
    "http://localhost:3000/",
    "http://localhost:3000/about",
    "http://localhost:3000/contact",
    "http://localhost:3000/products"
  ],
  "concurrency": 4
}
.github/workflows/a11y.yml
name: Accessibility Check
on: pull_request

jobs:
  a11y:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: npm ci
      - run: npm run build

      - name: Start preview server
        run: npm run preview &

      - name: Wait for server
        run: npx wait-on http://localhost:3000

      - name: Run Pa11y CI
        run: npx pa11y-ci
PRごとにPa11y CIを実行すると、アクセシビリティ違反が含まれるPRを自動でブロックできます。新しい違反を本番に入れない「ゲートキーパー」として機能します。

GitHub Actionsの詳しい設定はClaude Code GitHub Actions完全ガイドをご覧ください。

Storybook addon-a11yでコンポーネント単位のチェック

addon-a11yのセットアップ
npx storybook add @storybook/addon-a11y
.storybook/preview.ts(グローバル設定)
import type { Preview } from "@storybook/react";

const preview: Preview = {
  parameters: {
    a11y: {
      options: {
        runOnly: {
          type: "tag",
          values: ["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"],
        },
      },
    },
  },
};

export default preview;
ストーリー単位でのa11yチェック制御
const meta = {
  component: Button,
  parameters: {
    a11y: {
      test: "error", // "error" = テスト失敗 / "todo" = 警告のみ / "off" = スキップ
    },
  },
} satisfies Meta<typeof Button>;

Storybook MCPとの連携はClaude Code × Storybook完全ガイドで解説しています。

Claude Codeにアクセシビリティ違反を自動修正させる

axe-coreやPa11yで検出された違反をClaude Codeに渡すと、具体的な修正コードを生成できます。

アクセシビリティ修正プロンプト
Pa11y CIの結果、以下のWCAG違反が検出されました。
すべて修正してください。

1. /about: img要素にalt属性がない(WCAG 1.1.1)
2. /contact: フォームのinputにlabelが関連付けされていない(WCAG 1.3.1)
3. /products: テキストの色コントラスト比が3.2:1(AA基準4.5:1未満)(WCAG 1.4.3)
4. /: ボタンがdiv+onClickで実装されている(WCAG 2.1.1)
5. /: フォーカスインジケータがCSSでoutline:noneされている(WCAG 2.4.7)

各違反について修正コードを生成してください。

よくある違反パターンと修正例

div+onClick → button要素に修正
// NG: divにonClick(キーボード操作不可)
<div onClick={handleAction} className="btn">
  送信
</div>

// OK: button要素(キーボード操作・フォーカス・スクリーンリーダー自動対応)
<button onClick={handleAction} className="btn">
  送信
</button>
アイコンボタンにaria-labelを追加
// NG: スクリーンリーダーが「ボタン」としか読み上げない
<button onClick={onClose}><XIcon /></button>

// OK: ボタンの目的を伝える
<button onClick={onClose} aria-label="閉じる"><XIcon /></button>
フォームのlabel関連付け
// NG: labelとinputが関連付けされていない
<label>メールアドレス</label>
<input type="email" name="email" />

// OK: htmlForとidで関連付け
<label htmlFor="email">メールアドレス</label>
<input type="email" id="email" name="email" />

// OK: labelでinputをラップ
<label>
  メールアドレス
  <input type="email" name="email" />
</label>
フォーカストラップ(モーダルダイアログ)
import { useRef, useEffect } from "react";

interface DialogProps {
  isOpen: boolean;
  onClose: () => void;
  title: string;
  children: React.ReactNode;
}

export function Dialog({ isOpen, onClose, title, children }: DialogProps) {
  const dialogRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (isOpen) dialogRef.current?.focus();
  }, [isOpen]);

  if (!isOpen) return null;

  return (
    <div
      ref={dialogRef}
      role="dialog"
      aria-modal="true"
      aria-labelledby="dialog-title"
      tabIndex={-1}
      onKeyDown={(e) => e.key === "Escape" && onClose()}
    >
      <h2 id="dialog-title">{title}</h2>
      {children}
      <button onClick={onClose}>閉じる</button>
    </div>
  );
}
Radix UI / shadcn/uiを使っている場合、ダイアログ・ポップオーバー・メニュー等のARIA属性とフォーカス管理は自動で処理されます。自前でaria-modal/フォーカストラップを実装するのは、UI Primitiveを使っていない場合のみです。

よくある質問

Q自動テストだけでアクセシビリティ対応は完了しますか?
Aいいえ。axe-coreやPa11yで自動検出できるのはWCAG違反の約57%です。画像のalt属性が「適切か」(存在するかではなく)、キーボード操作が「自然に使えるか」、スクリーンリーダーで「意味が伝わるか」は自動テストでは判断できません。自動テストは「最低限の品質ゲート」として使い、定期的な手動テスト(スクリーンリーダー+キーボード操作)を併用してください。
Q日本の法律でWebアクセシビリティは義務ですか?
A2024年4月施行の障害者差別解消法改正により、民間事業者への合理的配慮の提供が義務化されました。ただしWebアクセシビリティ自体は「環境の整備」として努力義務です。しかし、障害のある利用者から申し出があった場合の対応は法的義務のため、事前にWCAG準拠しておくことが実務上の最善策です。直接的な罰則はありませんが、主務大臣による報告徴収・助言・指導・勧告があります。
QWCAG 2.2のAとAAの違いは何ですか?
AA(シングルA)は最低限の基準(テキスト代替、キーボード操作可能等)、AA(ダブルA)はほとんどの企業サイトが目標とすべき基準(色コントラスト4.5:1以上、フォーカスインジケータ、タッチターゲット24px以上等)です。AAAは最も厳格な基準で、すべてのページでの完全準拠は現実的ではないとされています。実務ではWCAG 2.2 AA準拠を目標にしてください。
QClaude Codeが生成するコンポーネントをアクセシブルにするにはどうすればよいですか?
ACLAUDE.mdにアクセシビリティルールを明記するのが最も効果的です。「すべての画像にalt」「div+onClick禁止」「色コントラスト4.5:1以上」「フォームにlabel関連付け必須」を書いておくだけで、Claude Codeの生成コードの品質が大きく変わります。さらにshadcn/ui(Radix UIベース)を使えばARIA属性・フォーカス管理が自動で処理されます。
Qaxe-coreのwithTagsにはどのタグを指定すればよいですか?
AWCAG 2.2 AA準拠を目標とする場合は["wcag2a", "wcag2aa", "wcag21a", "wcag21aa", "wcag22aa"]を指定します。これでWCAG 2.0/2.1/2.2のA・AA基準がすべてチェックされます。ベストプラクティスも含めたい場合は"best-practice"タグを追加してください。

まとめ

  • CLAUDE.mdにルール明記: アクセシビリティ基準を書いておくと、Claude Codeの生成コードが最初からWCAG準拠になる
  • eslint-plugin-jsx-a11y: コーディング時点でalt漏れ・label未関連付け・div+onClick等を静的検出
  • axe-core + Playwright: E2EテストにWCAGチェックを統合。ページ遷移ごとに自動検出
  • Pa11y CI + GitHub Actions: PRごとにアクセシビリティゲートを設置。違反を含むPRをブロック
  • Storybook addon-a11y: コンポーネント単位でWCAGチェック
  • 自動テストの限界: 検出率は約57%。手動テスト(スクリーンリーダー+キーボード操作)との併用が必須

テスト戦略全般はClaude Codeテスト完全ガイド、フロントエンド開発はClaude Codeフロントエンド開発ガイド、Storybook連携はClaude Code × Storybook完全ガイドもあわせてご覧ください。