axe-rules について
axe-rulesは、axe-coreのスキャンを作成、レビュー、デバッグするためのアクセシビリティ参考スキルです。ルールの重大度やWCAGのカバー範囲、CIでの利用方法をまとめ、手動テストと人による確認も重視します。
主な機能
- 01axe-coreルールを重大度別に整理
- 02WCAG自動検査の範囲を要約
- 03Playwright CIのスキャン例を提示
- 04結果確認と設定方法を解説
活用シーン
- 01axe-coreスキャンのリリース基準策定
- 02Playwright CIでのアクセシビリティ検査
- 03結果の確認と除外ルールの記録
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mgifford/ accessibility-skills --skill axe-rulesインストール後、Claude Code で/axe-rulesを入力して読み込まれたか確認します。
同梱ファイルSYNC.md
詳細
Axe-Core ルールリファレンススキル
正式な情報源:
mgifford/ACCESSIBILITY.mdのexamples/AXE_RULES_REFERENCE.mdおよびexamples/AXE_RULES_COVERAGE.mdこのスキルはこれらのファイルをもとに作成されています。判断に迷った場合は、例を正式な情報源としてください。 注: 正式なファイルは、特定のテストフィクスチャスキャナー プロジェクト(番号付きのテストページ)を中心に構成されています。このスキルでは、特定のフィクスチャに依存しない汎用的なリファレンスとして、同じルールセットと 重大度を再構成しています。
axe-core のスキャンを作成、レビュー、デバッグする際は、これらのルールを適用してください。
基本原則
Axe-core が自動的に検出できる WCAG の問題は約 30~40%です。これは最低基準であり、 上限ではありません。自動スキャンと手動でのキーボードおよびスクリーンリーダーのテストを 必ず組み合わせてください。
axe-core の結果は証拠であり、適合性の判定ではありません。 axe が報告したルールの
生の結果(violations、incomplete、passes、inapplicable)を
そのまま保持してください。プロジェクトの指摘事項に変換する際に、上書きしたり破棄したりしないでください。
WCAG との対応付けの根拠として、このファイル、AXE_RULES_REFERENCE.md、または
ルール固有の dequeuniversity.com/rules/axe/ ページを引用してください。そのルールについて
axe-core が文書化していない対応付けを作り出してはいけません。未レビューの violations の結果は、
人が確認するまでは、確定した規格違反ではなく、
evidence_status: automated-indicator、handling: review として記録してください。
アクセシビリティ指摘事項の追跡:ポリシー分類を参照してください。
スキャンに含める主要なタグ:
.withTags(['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa'])
Axe-core 4.11 には、次のカテゴリにわたる 100 以上の自動チェックが含まれています:WCAG 2.0 A/AA(68 ルール)、WCAG 2.1 A/AA(26 ルール)、WCAG 2.2 A/AA(1 ルール、デフォルトで無効)、 ベストプラクティス(30 以上のルール)、WCAG AAA(3 ルール、デフォルトで無効)、 実験的(9 ルール、デフォルトで無効)、および非推奨(7 ルール、デフォルトで無効)。
重大度スケール(axe-core)
| axe の重大度 | 意味 |
|---|---|
| critical | 1 つ以上の障害者グループのアクセスを妨げます |
| serious | アクセスを大幅に妨げます |
| moderate | 操作に支障が生じますが、回避策があります |
| minor | ベストプラクティスとの隔たりがあり、影響はわずかです |
重大なルール — 本番環境に絶対に含めてはいけません
| ルール ID | カテゴリ | 説明 |
|---|---|---|
image-alt | テキストによる代替 | <img> に alt 属性がありません |
area-alt | テキストによる代替 | イメージマップの <area> に代替テキストがありません |
input-image-alt | テキストによる代替 | <input type="image"> に代替テキストがありません |
video-caption | テキストによる代替 | <video> にキャプションがありません |
aria-allowed-attr | ARIA | 要素に、そのロールではサポートされない ARIA 属性があります |
aria-hidden-body | ARIA | <body> に aria-hidden が適用されています |
aria-required-attr | ARIA | 必須の ARIA 属性がありません |
aria-required-children | ARIA | 必須の子 ARIA ロールがありません |
aria-required-parent | ARIA | 必須の親 ARIA ロールがありません |
aria-roles | ARIA | ARIA ロールの値が無効です |
aria-valid-attr | ARIA | ARIA 属性名が無効です |
aria-valid-attr-value | ARIA | ARIA 属性の値が無効です |
label | フォーム | 関連付けられた <label> がないフォーム入力 |
select-name | フォーム | アクセシブルな名前がない <select> |
button-name | ボタン/リンク | 判別可能なテキストがないボタン |
input-button-name | ボタン/リンク | テキストがない <input type="button"> |
duplicate-id-aria | 構造 | ARIA から参照される id の値が重複しています |
meta-refresh | メタ | <meta http-equiv="refresh"> によって時間指定のリダイレクトが発生します |
重大なルール — リリース前に修正してください
| ルール ID | カテゴリ | 説明 |
|---|---|---|
object-alt | テキストによる代替 | アクセシブルなテキストがない <object> |
svg-img-alt | テキストによる代替 | role="img" が指定され、アクセシブルな名前がない SVG |
role-img-alt | テキストによる代替 | role="img" が指定された要素に代替テキストがない |
aria-braille-equivalent | ARIA | 点字ラベルに点字以外の同等の表記がない |
aria-command-name | ARIA | アクセシブルな名前がないボタン、リンク、またはメニュー項目 |
aria-conditional-attr | ARIA | ロールの仕様に反して ARIA 属性が使用されている |
aria-hidden-focus | ARIA | aria-hidden 要素にフォーカス可能なコンテンツが含まれている |
aria-input-field-name | ARIA | アクセシブルな名前がない ARIA 入力フィールド |
aria-meter-name | ARIA | アクセシブルな名前がない ARIA meter 要素 |
aria-progressbar-name | ARIA | アクセシブルな名前がない ARIA progressbar 要素 |
aria-prohibited-attr | ARIA | 禁止されている ARIA 属性が使用されている |
aria-toggle-field-name | ARIA | アクセシブルな名前がない ARIA トグルフィールド |
aria-tooltip-name | ARIA | アクセシブルな名前がない ARIA ツールチップ |
aria-dialog-name | ARIA | アクセシブルな名前がないダイアログ |
aria-treeitem-name | ARIA | アクセシブルな名前がないツリー項目 |
color-contrast | 色 | テキストのコントラスト比が 4.5:1(通常サイズ)または 3:1(大きな文字)を下回っている |
frame-title | フレーム | アクセシブルな名前がない <iframe> |
frame-title-unique | フレーム | フレームのタイトルが一意でない |
frame-focusable-content | フレーム | フォーカス可能なコンテンツを含むフレームに tabindex="-1" が設定されている |
html-has-lang | 言語 | <html> に lang 属性がない |
html-lang-valid | 言語 | lang 属性の値が無効な BCP 47 値である |
valid-lang | 言語 | インラインの lang 値が無効である |
document-title | 言語 | <title> 要素がない |
list | 構造 | <ul>/<ol> に <li> 以外の要素が含まれている |
listitem | 構造 | <ul> または <ol> の外に <li> がある |
definition-list | 構造 | <dl> に <dt>/<dd> 以外の要素が含まれている |
dlitem | 構造 | <dl> の外に <dt>/<dd> がある |
bypass | キーボード | ナビゲーションをスキップする仕組みがない |
scrollable-region-focusable | キーボード | スクロール可能な領域にキーボードでアクセスできない |
link-name | ボタン/リンク | 判別可能なテキストがないリンク |
link-in-text-block | ボタン/リンク | リンクが周囲のテキストと区別できない |
avoid-inline-spacing | コンテンツのサイズ調整 | テキスト間隔の上書きを調整できない |
autocomplete-valid | フォーム | autocomplete 属性が無効、または指定されていない |
tabindex | ベストプラクティス | 0 より大きい tabindex 値が使用されている |
label-title-only | ベストプラクティス | フォームフィールドが title 属性のみでラベル付けされている |
label-content-name-mismatch | ベストプラクティス(実験的) | 表示されるラベルのテキストがアクセシブルな名前と一致しない |
td-has-header | テーブル(実験的) | 大きなテーブルのセルに対応する見出しがない |
table-fake-caption | テーブル(実験的) | テーブルのキャプションが <caption> でマークアップされていない |
p-as-heading | ベストプラクティス(実験的) | 見出しのように見えるスタイルが適用された段落 |
中程度のルール — 近いうちのバックログで修正
| ルール ID | カテゴリ | 説明 |
|---|---|---|
heading-order | 見出し | 見出しレベルが飛んでいます(例:h1 → h3) |
empty-heading | 見出し | 見出しに判別可能なテキストがありません |
th-has-data-cells | テーブル | テーブル見出しに関連付けられたデータセルがありません |
td-headers-attr | テーブル | テーブルセルが無効な見出し ID を参照しています |
meta-viewport | メタ | ビューポートの user-scalable=no によりズームが無効になっています |
html-xml-lang-mismatch | 言語 | lang 属性と xml:lang 属性が一致していません |
form-field-multiple-labels | フォーム | フォームフィールドに競合するラベルが複数あります |
landmark-one-main | ベストプラクティス | ページに <main> ランドマークがありません |
landmark-banner-is-top-level | ベストプラクティス | banner ランドマークが最上位にありません |
landmark-contentinfo-is-top-level | ベストプラクティス | contentinfo ランドマークが最上位にありません |
landmark-main-is-top-level | ベストプラクティス | main ランドマークが最上位にありません |
landmark-no-duplicate-banner | ベストプラクティス | banner ランドマークが複数あります |
landmark-no-duplicate-contentinfo | ベストプラクティス | contentinfo ランドマークが複数あります |
landmark-no-duplicate-main | ベストプラクティス | main ランドマークが複数あります |
region | ベストプラクティス | ランドマーク領域の外にコンテンツがあります |
page-has-heading-one | ベストプラクティス | ページに <h1> がありません |
scope-attr-valid | ベストプラクティス | scope 属性の値が無効です |
accesskeys | ベストプラクティス | accesskey の値が一意ではありません |
軽微なルール
| ルール ID | カテゴリ | 説明 |
|---|---|---|
table-duplicate-name | テーブル | <caption> のテキストが summary 属性と重複しています |
aria-deprecated-role | ARIA | 非推奨の ARIA ロールが使用されています |
server-side-image-map | キーボード | サーバーサイドのイメージマップが使用されています |
aria-text | ARIA(ベストプラクティス) | フォーカス可能な子孫要素を持つ要素に role="text" が指定されています |
デフォルトで無効になっているルール(非推奨の marquee/blink/audio-caption)は上記に記載していません。該当するものがあれば報告してください。ただし、デフォルトのスキャンでは有効になっていません。
axe-core がデフォルトで無効にしている 3 つの WCAG AAA ルールは、プロジェクトが目標とする AA では要求されないレベルに対して報告します。有効にした場合、プロジェクトがより広い目標を宣言していなければ、これらのルールによる確認済みの指摘は advisory ではなく obligation: aspirational に分類してください。これは実際の AAA レベルの指摘ですが、AA の基準には含まれません。これらのルールを満たしていることを WCAG AAA 準拠として報告しないでください。
CI で axe-core を実行する(Playwright)
import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';
test('No WCAG 2.x AA violations', async ({ page }) => {
await page.goto('/');
const results = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa'])
.analyze();
expect(results.violations).toEqual([]);
});
一般的な設定オプション:
// Exclude a specific element (use sparingly — document the reason)
.exclude('#known-false-positive')
// Include only a specific element
.include('#component-under-test')
// Disable a specific rule (document the reason and JIRA/issue link)
.disableRules(['color-contrast'])
完了の定義チェックリスト
-
wcag2a、wcag2aa、wcag21aa、wcag22aaタグを使用して、すべての PR で axe-core のスキャンを実行する - 本番コードに重大な違反がない
- 本番コードに深刻な違反がない(または、課題へのリンクを含む明示的な免除がある)
- すべてのルール除外について、理由と関連する課題を記録する
- ライトモードとダークモードの両方でテストする
- モバイルのビューポートでテストする
- 参照用に axe の結果を CI アーティファクトとして公開する
主な WCAG 基準(自動化によるカバー範囲)
- 1.1.1 非テキストコンテンツ(A)
- 1.3.1 情報及び関係性(A)
- 1.4.3 コントラスト(最低限)(AA)
- 2.4.2 ページのタイトル(A)
- 3.1.1 ページの言語(A)
- 4.1.2 名前、役割及び値(A)
- 4.1.3 ステータスメッセージ(AA)— カバー範囲は部分的
自動化でカバーできる WCAG の問題は約 30~40%です。必ず手動テストも併せて実施してください。
参考資料
基準の展望: これらのルールは WCAG 2.2 AA を対象としています。 https://www.w3.org/TR/wcag-3.0/ を監視してください。