mcpField
A
accessibility-auditor

accessibility-auditor

github.com/davila7デザイン・UI33.0k438 回インストール今日更新
リポジトリ

accessibility-auditor について

accessibility-auditor は、Web のアクセシビリティを監査・改善するチーム向けのガイダンスです。WCAG の実践、よくある問題の修正、ARIA、自動・キーボード・スクリーンリーダーによるテストを説明します。

主な機能

  1. 01WCAG 2.1 のガイダンス
  2. 02よくある問題の修正
  3. 03ARIA 属性とランドマーク
  4. 04自動テストのチェックリスト
  5. 05キーボード操作のテスト
  6. 06スクリーンリーダーのテスト

活用シーン

  1. 01WCAG に沿ったサイト監査
  2. 02ラベルや代替テキストの修正
  3. 03キーボードのみでの操作確認
  4. 04スクリーンリーダーでのページ検証

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/davila7/claude-code-templates --skill accessibility-auditor

インストール後、Claude Code で/accessibility-auditorを入力して読み込まれたか確認します。

詳細

アクセシビリティ監査ツール

WCAG 標準に準拠し、あらゆる能力のユーザーに効果的に対応する、アクセシブルな Web 体験を作成するための包括的なガイドです。

このスキルを使用するタイミング

次の場合にこのスキルを使用してください:

  • Web サイトのアクセシビリティ準拠を監査するとき
  • WCAG 2.1 レベル AA または AAA 基準を実装するとき
  • アクセシビリティの違反やエラーを修正するとき
  • スクリーンリーダー(NVDA、JAWS、VoiceOver)でテストするとき
  • キーボードナビゲーションが正しく動作することを確認するとき
  • ARIA 属性とランドマークを実装するとき
  • ADA または Section 508 準拠の監査に備えるとき
  • インクルーシブなユーザー体験を設計するとき

WCAG 2.1 の原則(POUR)

1. 知覚可能(Perceivable)

ユーザーは提示される情報を知覚できる必要があります。

2. 操作可能(Operable)

ユーザーはインターフェースを操作できる必要があります。

3. 理解可能(Understandable)

ユーザーは情報とインターフェースを理解できる必要があります。

4. 堅牢(Robust)

コンテンツは、現在および将来の技術で動作するのに十分な堅牢性を持つ必要があります。

よくあるアクセシビリティの問題と修正方法

1. 画像の代替テキストの欠落

❌ 問題:

<img src="/products/shoes.jpg">

✅ 解決策:


<img src="/products/shoes.jpg" alt="Red Nike Air Max running shoes with white swoosh">


<img src="/decorative-pattern.svg" alt="" role="presentation">


<a href="/">
  <img src="/logo.png" alt="Company Name - Home">
</a>

ルール:

  • 情報を伝える画像: 内容や機能を説明する
  • 装飾的な画像: 空の alt(alt="")を使用する
  • 機能的な画像: 操作内容を説明する
  • 複雑な画像: 近くに詳細な説明を用意する
2. 低いカラーコントラスト

❌ 問題:

/* Contrast ratio 2.5:1 - Fails WCAG */
.text {
  color: #767676;
  background: #ffffff;
}

✅ 解決策:

/* Contrast ratio 4.5:1+ - Passes AA */
.text {
  color: #595959;
  background: #ffffff;
}

/* Contrast ratio 7:1+ - Passes AAA */
.text-high-contrast {
  color: #333333;
  background: #ffffff;
}

要件:

  • 通常のテキスト(18px 未満): 最低 4.5:1(AA)、強化 7:1(AAA)
  • 大きいテキスト(18px 以上または 14px 以上の太字): 最低 3:1(AA)、強化 4.5:1(AAA)
  • UI コンポーネントとグラフィック: 最低 3:1
3. セマンティクスのない HTML

❌ 問題:

<div class="button" onclick="submitForm()">Submit</div>
<div class="heading">Page Title</div>
<div class="nav-menu">...</div>

✅ 解決策:

<button type="submit" onclick="submitForm()">Submit</button>
<h1>Page Title</h1>
<nav aria-label="Main navigation">...</nav>

セマンティック要素:

  • ボタンには <button>
  • リンクには <a>
  • 見出し(階層構造)には <h1> 〜 <h6>
  • ランドマークには <nav>、<main>、<aside>、<article>、<section>
  • リストには <ul>、<ol>、<li>
  • 表形式のデータには <table>、<th>、<td>
4. フォームラベルの欠落

❌ 問題:

<input type="email" placeholder="Enter your email">

✅ 解決策:


<label for="email">Email Address</label>
<input type="email" id="email" name="email">


<label>
  Email Address
  <input type="email" name="email">
</label>


<label for="search" class="sr-only">Search</label>
<input type="text" id="search" placeholder="Search...">

ベストプラクティス:

  • すべてのフォームフィールドには、関連付けられたラベルが必要です
  • ラベルは表示されている必要があります(プレースホルダーに頼らないでください)
  • 視覚的なラベルが不可能な場合にのみ aria-label を使用してください
  • 関連するフィールドは <fieldset> と <legend> でグループ化してください
5. キーボードナビゲーションの問題

❌ 問題:

<div onclick="handleClick()">Click me</div>
<a href="javascript:void(0)" onclick="doSomething()">Action</a>

✅ 解決策:


<button onclick="handleClick()">Click me</button>


<div
  role="button"
  tabindex="0"
  onclick="handleClick()"
  onkeydown="handleKeyPress(event)"
>
  Click me
</div>

<script>
function handleKeyPress(event) {
  if (event.key === 'Enter' || event.key === ' ') {
    event.preventDefault();
    handleClick();
  }
}
</script>

キーボードの要件:

  • すべての対話的要素はキーボードで操作可能である必要があります
  • フォーカスインジケーターを視覚的に表示してください(アウトラインまたはカスタムスタイル)
  • タブ順序は視覚的な流れに沿った論理的なものにしてください
  • 繰り返し表示されるコンテンツには、スキップリンクを設けてください
  • キーボードトラップを作らないでください(ユーザーが他の場所へ移動できること)
6. ARIA ランドマークの欠落

❌ 問題:

<div class="header">...</div>
<div class="main-content">...</div>
<div class="sidebar">...</div>
<div class="footer">...</div>

✅ 解決策:

<header role="banner">
  <nav aria-label="Main navigation">...</nav>
</header>

<main role="main">
  <h1>Page Title</h1>
  <article>...</article>
</main>

<aside role="complementary" aria-label="Related articles">
  ...
</aside>

<footer role="contentinfo">
  ...
</footer>

一般的なランドマーク:

  • banner - サイトのヘッダー
  • navigation - ナビゲーションメニュー
  • main - 主要コンテンツ(ページごとに 1 つ)
  • complementary - 補足コンテンツ
  • contentinfo - サイトのフッター
  • search - 検索機能
  • form - フォームの領域
7. アクセシブルでないモーダル/ダイアログ

❌ 問題:

<div class="modal">
  <div class="content">
    Modal content
    <button onclick="closeModal()">Close</button>
  </div>
</div>

✅ 解決策:

<div
  role="dialog"
  aria-modal="true"
  aria-labelledby="modal-title"
  aria-describedby="modal-desc"
>
  <h2 id="modal-title">Confirm Action</h2>
  <p id="modal-desc">Are you sure you want to delete this item?</p>

  <button onclick="confirmAction()">Confirm</button>
  <button onclick="closeModal()">Cancel</button>
</div>

<script>
// Focus management
function openModal() {
  const modal = document.querySelector('[role="dialog"]');
  const focusableElements = modal.querySelectorAll(
    'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
  );

  // Store previous focus
  previousFocus = document.activeElement;

  // Focus first element
  focusableElements[0].focus();

  // Trap focus
  modal.addEventListener('keydown', trapFocus);
}

function closeModal() {
  // Return focus
  if (previousFocus) previousFocus.focus();
}

function trapFocus(event) {
  if (event.key !== 'Tab') return;

  const focusableElements = Array.from(
    modal.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')
  );

  const firstElement = focusableElements[0];
  const lastElement = focusableElements[focusableElements.length - 1];

  if (event.shiftKey && document.activeElement === firstElement) {
    lastElement.focus();
    event.preventDefault();
  } else if (!event.shiftKey && document.activeElement === lastElement) {
    firstElement.focus();
    event.preventDefault();
  }
}
</script>

モーダルの要件:

  • role="dialog" または role="alertdialog"
  • モーダルとして動作することを示す aria-modal="true"
  • タイトルを指す aria-labelledby
  • 説明用の aria-describedby(任意)
  • フォーカス管理(閉じ込めと復元)
  • Escape キーで閉じる
  • 背景のスクロールを防止する
8. スキップリンクの欠落

✅ 解決策:

<a href="#main-content" class="skip-link">
  Skip to main content
</a>

<header>
  <nav>...</nav>
</header>

<main id="main-content" tabindex="-1">
  
</main>

<style>
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: #000;
  color: #fff;
  padding: 8px;
  text-decoration: none;
  z-index: 100;
}

.skip-link:focus {
  top: 0;
}
</style>

ARIA のベストプラクティス

ARIA 属性リファレンス

状態:

  • aria-checked - チェックボックス/ラジオボタンの状態
  • aria-disabled - 無効状態
  • aria-expanded - 展開/折りたたみの状態
  • aria-hidden - 支援技術から非表示
  • aria-pressed - トグルボタンの状態
  • aria-selected - 選択状態

プロパティ:

  • aria-label - アクセシブルな名前
  • aria-labelledby - ラベルの ID 参照
  • aria-describedby - 説明の ID 参照
  • aria-live - ライブリージョンの更新
  • aria-required - 必須フィールド
  • aria-invalid - 検証状態
ライブリージョン

<div aria-live="polite" aria-atomic="true">
  Item added to cart
</div>


<div aria-live="assertive" role="alert">
  Error: Payment failed
</div>


<div role="status" aria-live="polite">
  Saving changes...
</div>
カスタムコンポーネント

アコーディオン:

<div class="accordion">
  <button
    aria-expanded="false"
    aria-controls="panel-1"
    id="accordion-1"
  >
    Section 1
  </button>
  <div id="panel-1" role="region" aria-labelledby="accordion-1" hidden>
    Panel content
  </div>
</div>

タブ:

<div role="tablist" aria-label="Content sections">
  <button
    role="tab"
    aria-selected="true"
    aria-controls="panel-1"
    id="tab-1"
  >
    Tab 1
  </button>
  <button
    role="tab"
    aria-selected="false"
    aria-controls="panel-2"
    id="tab-2"
    tabindex="-1"
  >
    Tab 2
  </button>
</div>

<div role="tabpanel" id="panel-1" aria-labelledby="tab-1">
  Panel 1 content
</div>
<div role="tabpanel" id="panel-2" aria-labelledby="tab-2" hidden>
  Panel 2 content
</div>

テストチェックリスト

自動テスト
  • axe DevTools または WAVE ブラウザ拡張機能を実行する
  • HTML の検証を行う(W3C Validator)
  • 色のコントラスト比をテストする
  • 見出しの階層構造を確認する
  • 代替テキストの欠落がないか確認する
手動テスト
  • キーボードのみ(Tab、Enter、Escape、矢印キー)でサイト全体を操作する
  • スクリーンリーダー(NVDA、JAWS、VoiceOver)でテストする
  • フォーカスインジケーターが表示されていることを確認する
  • フォームの検証メッセージが読み上げられることを確認する
  • モーダルのフォーカストラップをテストする
  • スキップリンクが機能することを確認する
  • ブラウザのズームを 200% にしてテストする
  • さまざまなビューポートサイズでページのリフローを確認する
  • JavaScript を無効にして、基本機能が動作することを確認する
  • Windows ハイコントラストモードでテストする
スクリーンリーダーテスト

VoiceOver(Mac):

  • 有効化: Cmd + F5
  • 移動: Control + Option + 矢印キー
  • すべて読み上げ: Control + Option + A

NVDA(Windows):

  • 移動: 矢印キー(ブラウズモード)または Tab(フォーカスモード)
  • すべて読み上げ: NVDA + 下矢印キー
  • 要素リスト: NVDA + F7

テストシナリオ:

  • ユーザーはページの構造を理解できるか?
  • 見出しは内容を適切に示し、階層化されているか?
  • フォームのラベルは明確で、入力欄に正しく関連付けられているか?
  • エラーメッセージは読み上げられるか?
  • ユーザーは視覚に頼らず主要なタスクを完了できるか?

アクセシビリティ声明

ウェブサイトに以下を掲載してください:

# Accessibility Statement

We are committed to ensuring digital accessibility for people with disabilities. We continually improve the user experience for everyone and apply relevant accessibility standards.

## Conformance Status
This website is partially conformant with WCAG 2.1 Level AA. "Partially conformant" means that some parts of the content do not fully conform to the accessibility standard.

## Feedback
We welcome your feedback on the accessibility of this site. Please contact us:
- Email: [email protected]
- Phone: +1-555-0123

## Known Issues
- [List any known accessibility issues and planned fixes]

Last updated: [Date]

リソース

ツール:

  • axe DevTools(ブラウザ拡張機能)
  • WAVE(Web アクセシビリティ評価ツール)
  • Lighthouse(Chrome DevTools)
  • Colour Contrast Analyser
  • スクリーンリーダー: NVDA、JAWS、VoiceOver

ガイドライン:

アクセシビリティは任意ではなく、インクルーシブなウェブ体験を作るための基本的な要件です。個々のプロジェクトの初期段階から優先的に取り組み、後回しにしないでください。

コメント