Web サイトのアクセシビリティ(a11y)対応、ついつい開発の終盤まで後回しにしてしまっていませんか?

「WCAG 2.1/2.2 Level AA を遵守する必要があるのは理解しているけれど……」と感じつつも、「WAI-ARIA の仕様が複雑で学習コストが高い」「動的 UI のキーボード操作処理を入れるとコードが煩雑になる」といった理由から、後回しになりがちなケースは少なくありません。その結果、リリース直前の手動チェックで膨大な修正が発生してしまうのは、フロントエンド開発においてよくある悩みです。

しかし、開発の設計・実装段階から AI をパートナーとして組み込む「シフトレフト」のアプローチを取り入れることで、この負担は大幅に軽減できます。

本記事では、フロントエンド開発の現場ですぐに活用できる 2大 AI ツール「GitHub Copilot」「Claude Code」を組み合わせた、アクセシビリティ対応の効率化ワークフローをご紹介します。チームで使える設定ファイルの例や実践的なコードも解説しますので、ぜひ参考にしてみてください。

2大 AI ツールの役割分担(どちらをいつ使う?)

アクセシビリティ対応を AI で効率化する際、重要なのは「1つのツールにすべてを任せる」のではなく、それぞれの強みに合わせて役割を分担させることです。

エディタ内でリアルタイムに実装をサポートしてくれる「GitHub Copilot」と、ターミナルからリポジトリ全体を俯瞰して一括修正してくれる「Claude Code」。この 2つの得意分野を把握することが、スムーズな運用の第一歩となります。

【コーディング中】   GitHub Copilot(VS Code 等でリアルタイム補完)
        ↓
【一括改修・テスト】 Claude Code(ターミナルでコード監査・レポート出力)

1. GitHub Copilot:タイピングの流れを止めないインライン支援

  • 主な実行環境:VS Code などの統合開発環境(IDE)
  • 得意な領域:タイピング中のセマンティック HTML や WAI-ARIA 属性のリアルタイム補完
  • 活用イメージ:コードを記述している最中に「ここは div ではなく button を使うべき」「aria-expanded も合わせて付与しておこう」といった適切な提案を低遅延で行なってくれます。後述する指示ファイルをリポジトリ内に配置しておくことで、チーム独自のアクセシビリティ規約を補完エンジンへ常時反映させることができます。

2. Claude Code:リポジトリ全域を自律的に監査・改修

  • 主な実行環境:ターミナル(CLI 環境)
  • 得意な領域:複数ファイルにまたがるコードの一括リファクタリング、自動テストとの連携・自己修復

  • 活用イメージ:プロジェクト全体のコードベースを一括で解析するのが非常に得意です。ガイドライン違反の箇所を検出して自動修正するだけでなく、axe-core などの自動テストツールと連携し、「テストが合格するまで自律的にコードを修正するループ」を回すことができます。

開発フェーズ別ワークフロー&実践コード例

ここからは、実際の開発の流れ(コーディング → 一括改修 → 自動テスト)に沿って、具体的な活用方法を見ていきましょう。今回は構造をシンプルにし、理解しやすさを重視して HTML と Vanilla JavaScript での実装例をご紹介します。


Phase 1:コーディング段階(Copilot にルールを認識させる)

まずはエディタでコードを書く段階です。Copilot に対して「このプロジェクトではアクセシビリティを重視する」という共通ルールを認識させるため、リポジトリ直下に指示ファイルを作成します。

1. 設定ファイル:.github/copilot-instructions.md の作成

このファイルを配置することで、Copilot が生成・提案するコードの品質をチーム全体で統制できます。
下記は記述例です。

# Front-End Accessibility (a11y) 指針

コード(HTML / CSS / JavaScript)を補完・生成する際は、以下の基準を厳格に遵守してください。

1. **セマンティック HTML の優先**:
   - `div` や `span` に直接クリックイベントを付与せず、必ず `button` や `nav` などのネイティブ要素を使用してください。
2. **フォームの構造化**:
   - すべての `input` には、`for` 属性と `id` 属性で適切に紐付けた `label` を必ず設置してください。
   - 動的なエラーメッセージは `aria-describedby` で入力欄と紐付け、`aria-live="polite"` を指定した領域に表示させてください。
3. **属性と ARIA プロパティの正しい使い方**:
   - ARIA プロパティと属性もしくは暗黙の属性で同等のセマンティクスを重複させないようにしてください。
   - 例えば、`input required` に対して `aria-required="true"` を付与する必要はありません。

2. Copilot によるコード自動補完の例

設定ファイルを配置した状態でフォームの記述を始めると、以下のようにアクセシビリティに配慮された構造が自動補完されます。

<!-- Copilot が提案したアクセシブルな入力フォームの例 -->

  <!-- label と input が for / id 属性で正しく紐付けられている -->
  <label for="user-email" class="label"> メールアドレス <span aria-hidden="true">*</span> </label>



  <!-- エラー発生時、スクリーンリーダーへ割り込みなしで動的に通知される -->
  <div id="email-error-msg" aria-live="polite" class="error-message">正しいメールアドレスの形式で入力してください。</div>


Phase 2:リファクタリング段階(Claude Code による一括監査と修正)

コンポーネントがある程度組み上がった段階や既存コードを改修する際は、ターミナルから Claude Code を実行し、一括で監査と修正を行ないます。

1. 設定ファイル:CLAUDE.md の定義

プロジェクトルートに配置し、Claude Code がコードを変更する際の必須要件を記述しておきます。

# アクセシビリティ必須要件(NON-NEGOTIABLE)

コードを変更する際は、以下の原則を厳守すること:

- WAI-ARIA 属性を付与する前に、まずは適切なネイティブ HTML タグの使用を優先すること。
- すべての操作可能要素は、キーボード(Tab, Enter, Space, Esc)のみで操作可能にすること。
- モーダルダイアログを実装する際は、独自のフォーカストラップを組むのではなく、必ずネイティブの `` 要素を使用し、JavaScript の `showModal()` と `close()` で制御すること。

2. Claude Code への改修指示プロンプト例(モーダルダイアログの改善)

実装の不備が発生しやすいモーダルダイアログについて、Claude Code に修正を指示します。

ターミナルでの入力プロンプト例:
src/modal.html および src/modal.js を WCAG 2.1 AA 規格に準拠するようにリファクタリングしてください。
【必須要件】

  1. ネイティブの “ 要素を使用すること。
  2. showModal() を用いて、ブラウザ標準の Focus Trap と Esc キーでの閉じる処理を有効化すること。

3. Claude Code による自動修正結果

【HTML 構造】

<!-- 呼び出し元ボタン -->
<button id="open-modal-btn" type="button">お知らせを見る</button>

<!-- モーダル本体(dialog 要素を使用することで ARIA 属性の多くが不要になる) -->
<dialog id="modal" aria-labelledby="modal-title" class="modal-overlay">
  <div class="modal-content">
    <h2 id="modal-title">お知らせ</h2>
    <p>Web アクセシビリティ対応を AI で効率化します。</p>

    <!-- 閉じるボタン(autofocus を付与して開いた直後にフォーカスを当てる) -->
    <button id="close-modal-btn" type="button" autofocus aria-label="ダイアログを閉じる">閉じる</button>
  </div>
</dialog>

【JavaScript ロジック】

// Claude Code が作成したモダンな制御ロジック
const openBtn = document.getElementById("open-modal-btn");
const closeBtn = document.getElementById("close-modal-btn");
const modal = document.getElementById("modal");

// 1. 開く処理:showModal() を使うことで Focus Trap や Esc 閉じがブラウザ標準で機能する
openBtn.addEventListener("click", () => {
  modal.showModal();
});

// 2. 閉じる処理
closeBtn.addEventListener("click", () => {
  modal.close();
});

// ※ close() が呼ばれた後、フォーカスは自動的に呼び出し元(openBtn)へ復元されます

Phase 3:テスト・検証段階(Claude Code × 自動テストツール)

実装した Web ページ群がアクセシビリティ標準(WCAG)を満たしているか検証します。

もちろん、この工程をまるっと Claude Code に丸投げすることも可能ですが、毎回 Claude Code にパッケージの選択やセットアップから行なわせると、コマンド実行のやり取りが増えてトークンと実行時間を大きく消費します。そのため、事前での環境構築・全ページ対応の汎用テストテンプレート作成・CLAUDE.md への記述の 3点をセットにしトークン効率を最大化します。
また、自動修正でデザインとのズレが生じるなどを考慮し、修正は手作業で行なう運用がベストプラクティスと考えました。

STEP 1:必要パッケージの手動インストール

必要なパッケージはプロジェクトの開発依存(devDependencies)として、あらかじめ手動でインストールしておきます。AI にインストールの判断や試行をさせないことで、無駄なトークン消費をカットできます。

npm install -D @playwright/test @axe-core/playwright
npx playwright install # ブラウザバイナリのインストール

STEP 2:全ページ対応の静的チェック汎用テンプレートを用意

プロジェクト内の全 HTML ファイルを自動検出して初期表示時のアクセシビリティ違反を網羅的に検証するテンプレート(tests/a11y.spec.js)を 1つ用意しておきます。これにより、今後新しい HTML ページが増えてもテストコードを書き換える必要がなくなります。

// tests/a11y.spec.js
import { test, expect } from "@playwright/test";
import AxeBuilder from "@axe-core/playwright";
import fs from "fs";
import path from "path";

// src配下の全HTMLファイルを再帰的に取得する関数
function getHtmlFiles(dir) {
  let files = [];
  if (!fs.existsSync(dir)) return files;

  const items = fs.readdirSync(dir, { withFileTypes: true });

  for (const item of items) {
    const fullPath = path.join(dir, item.name);
    if (item.isDirectory()) {
      files = files.concat(getHtmlFiles(fullPath));
    } else if (item.name.endsWith(".html")) {
      files.push(fullPath);
    }
  }
  return files;
}

const htmlFiles = getHtmlFiles("./src");

// 全ページの初期表示(静的)アクセシビリティ自動検証
test.describe("全ページの静的アクセシビリティ検証", () => {
  for (const filePath of htmlFiles) {
    const relativePath = path.relative(process.cwd(), filePath);

    test(`初期表示チェック: ${relativePath}`, async ({ page }) => {
      await page.goto(`file://${path.resolve(filePath)}`);

      const accessibilityScanResults = await new AxeBuilder({ page }).analyze();
      expect(accessibilityScanResults.violations).toEqual([]);
    });
  }
});

STEP 3:CLAUDE.md にショートカット指示を登録

Claude Code が勝手にコードを書き換えずに、エラーレポートだけを的確に出力するよう指示を更新します。

# テスト・アクセシビリティ検証ルール

## コマンド

- a11yテスト実行: `npx playwright test tests/a11y.spec.js`

## 注意事項

- `@axe-core/playwright` は導入済みです。追加の `npm install` は実行しないでください。
- テスト実行時にエラー(Violations)が検出された場合は、ソースコードを直接修正せず、**「違反が発生しているファイル名」「対象の HTML 要素」「違反内容の要約(WCAG 規約)」を一覧形式でターミナルに出力**してください。

STEP 4:Claude Code へのレポート要求と手動修正

エンジニアは CLI で検証とエラー出力のみを指示します。

$ claude "a11yテストを実行し、検出されたエラー一覧をわかりやすく出力してください"

実行結果の出力イメージ:

検出されたアクセシビリティ違反(2件)

  1. src/index.html (L12): button にアクセシブルな名前(テキストまたは aria-label)がありません。
  2. src/modal.html (L45): コントラスト比が不足しています(現行 2.8:1 / 推奨 4.5:1 以上)。

出力されたリストを確認し、エンジニアがコンテキストやデザイン意図を考慮しながら src/index.htmlsrc/modal.html を手動で修正します。

AI 活用における注意点とエンジニアによる最終検証

AI は開発効率を劇的に向上させてくれますが、生成されたコードを盲信することにはリスクも伴います。

AI が起こしやすい不具合のパターン

  • 過剰な ARIA 属性の付与(Over-ARIA): ネイティブの button タグに対して、不必要に role="button"tabindex="0" を二重付与するようなコードを生成することがあります。これは支援技術側で予期せぬ挙動を引き起こす原因となります。
  • 複雑な動的制御の不備: 単純な構造であれば問題なくても、非同期通信や複雑な状態変化が絡む画面では、フォーカス移動やアナウンスのタイミングで論理的な欠損を残すケースが見られます。

自動チェックで検出できる不備は全体の 3〜4割

自動テストツール(axe-core 等)や AI による静的解析で検出可能なアクセシビリティ違反は、全体の 30%〜40% 程度と言われています。残りの 60% 以上は、実際のユーザー体験に基づいた文脈的な判断が必要です。

そのため、AI によるコード作成後は、必ずエンジニア自身による以下の 3つの手動検証を行なわなければなりません。

  1. 物理キーボードによるナビゲーション確認
    キーボードのみ(Tab / Shift+Tab / Enter / Space / Esc)で、すべての操作可能要素に問題なくアクセスでき、フォーカスが論理的な順序で移動するかを確認します。
  2. スクリーンリーダーを用いた音声動作確認
    macOS VoiceOver や Windows NVDA などの実機を使用し、読み上げ順序や動的変更(aria-live)の通知タイミングが自然であるかを実際に耳で確認します。

  3. 視覚的なフォーカス表示の確認
    Tab キーでフォーカスを移動させた際、フォーカスリング(focus-visible)があらゆる背景色において明確に視認できるか目視で確認します。

まとめ

アクセシビリティ対応は、開発の最終段階でまとめて実施しようとすると膨大な手戻りが発生します。

  • エディタ内では GitHub Copilot を活用してリアルタイムに標準的な構造を補完する
  • ターミナルからは Claude Code を活用して一括修正と自動テストの修正ループを回す

この 2つの AI ツールを日々の開発ワークフローに適切に組み込むことで、対応に伴う負担や心理的ハードルは大幅に下がるはずです。

AI を強力な「実装アシスタント」として使いこなしつつ、最終的なユーザビリティの品質保証責任はエンジニアが担う体制を整えて、誰もが快適に利用できる Web サイトを目指していきましょう。