accessibility について
選択した WCAG 2.2 レベルと対象プラットフォームに基づき、Flutter アプリのアクセシビリティを監査・修正するワークフロースキルです。段階的な監査からコード付きの指摘、範囲を指定した修正までを扱います。
主な機能
- 01WCAG 2.2 レベルの選択
- 02プラットフォーム別 Flutter 検査
- 037 分野のアクセシビリティ監査
- 04重要度と Dart 修正コードの提示
- 05修正範囲の選択と回帰テスト
活用シーン
- 01指定した WCAG レベルで Flutter ウィジェットを監査
- 02対象プラットフォーム別のアクセシビリティ確認
- 03コード差分付きで修正可能な問題を提示
- 04優先度に沿った修正と回帰テストの追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ verygoodopensource/ vgv-ai-flutter-plugin --skill accessibilityインストール後、Claude Code で/accessibilityを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
agents/openai.yamlreferences/audit-templates.mdexamples.mdtesting.mdwcag-criteria.mdwidget-mapping.mdreferences/platforms/android.mdios.mdlinux.mdmacos.mdweb.mdwindows.md詳細
アクセシビリティ
WCAG 2.2 の適合レベル A、AA、AAA にわたる Flutter のアクセシビリティ監査と修正を行います。このファイルはワークフローです。追加リソースに記載されているリファレンスファイルは必要に応じて読み込み、以下の各フェーズでは必要なファイルを指定しています。
現在のフェーズで指定されているファイルのみを読み込んでください。
コア基準
すべてのアクセシビリティ作業に、以下の基準を適用してください。
適合レベル — 監査を始める際は必ず、プロジェクトが目標とする WCAG 2.2 の適合レベル(A、AA、AA + 選択した AAA、または AAA)を確認してください。AA と決めつけないでください。
プラットフォームの選択 — 監査を始める際は必ず、対象となる 6 つのプラットフォーム(iOS、Android、Web、macOS、Windows、Linux)を確認してください。references/platforms/ にある該当ファイルのプラットフォームルールを適用してください。
画像のセマンティクス(WCAG 1.1.1)— すべての Image に semanticLabel を設定するか、Semantics(label:) でラップしてください。装飾用画像には excludeFromSemantics: true を指定してください。
ジェスチャー検出(WCAG 2.1.1)— タップ対象に GestureDetector を単独で使用しないでください。InkWell、ElevatedButton、TextButton、または IconButton を使用してください。GestureDetector はポインター操作専用であり、キーボードやスイッチアクセスでは到達できません。
ターゲットサイズ(WCAG 2.5.8)— AA でのターゲットサイズの最小値は 24x24 CSS px(≈ 24 dp)です。VGV が推奨する最小値は 48x48 dp です。24 dp 以上 48 dp 未満の対象は、AA では VGV スタイルの指摘として、AAA では 2.5.5(44 dp)に基づく WCAG の指摘として報告してください。
ドラッグの代替手段(WCAG 2.5.7)— ドラッグ操作を必要とするすべての機能には、同じ画面上にドラッグ以外の代替手段を用意してください。スライダーにはキーボードまたはステッパーで操作する代替手段が必要です。Dismissible には明示的な削除ボタンが必要です。ReorderableListView には上下移動または「移動先」コントロールが必要です。
フォーカスを遮らない(WCAG 2.4.11)— フォーカス中のウィジェットが、固定ヘッダー、スナックバー、ボトムシート、固定表示の FAB、またはオーバーレイによって完全に隠されないようにしてください。Scrollable.ensureVisible と Scaffold.resizeToAvoidBottomInset: true を使用してください。
色の識別(WCAG 1.4.1)— 色だけを識別手段として使用しないでください。必ずラベル、アイコン、または形状を組み合わせてください。
アニメーションとモーション(WCAG 2.3.3)— すべてのアニメーションで MediaQuery.disableAnimations を尊重してください。すべての AnimationController、AnimatedContainer、Hero トランジション、PageRouteBuilder トランジションを、このフラグに応じて制御してください。
アイコンボタン(WCAG 4.1.2)— アイコンのみのボタンには Tooltip または Semantics(label:) を設定してください。スクリーンリーダーが目的を伝えるほかの方法はありません。
セマンティクスの除外(WCAG 1.1.1)— 装飾用ではないコンテンツに ExcludeSemantics を使用しないでください。これを使うと、そのサブツリー全体がセマンティクスツリーから取り除かれるため、その中にあるボタンやその他のコントロールは TalkBack と VoiceOver から消え、スクリーンリーダーのユーザーが操作できなくなります。操作可能なコンテンツをラップする依頼を断る際は、この結果を説明してください。スクリーンリーダーが子要素ごとに停止しないようにするには、静的なラベルと値のペアのみを MergeSemantics で囲み、インタラクティブな兄弟要素は外に置いて、それぞれにフォーカスできるようにしてください。
テキストコンテナー(WCAG 1.4.4)— 固定高さのコンテナー内に Text を配置しないでください。minHeight 制約を使用してください。固定高さでは、Android ではフォントスケール 1.5x でテキストが切り取られます。iOS では「さらに大きな文字」設定が約 3.1x に達するため、それより早く切り取られます。
コントラスト(WCAG 1.4.3)— すべてのテキストと UI コンポーネントは、選択した WCAG レベルのコントラスト比を満たす必要があります。詳細は references/wcag-criteria.md を参照してください。
Cupertino のセマンティクス(WCAG 4.1.2)— Cupertino ウィジェット(CupertinoSwitch、CupertinoSlider、CupertinoSegmentedControl、CupertinoButton)には、Material の同等ウィジェットより弱いセマンティクスのデフォルト設定が適用されています。必ず Semantics(label:, value:, button:) でラップしてください。
自動入力ヒント(WCAG 1.3.5)— 構造化された個人データ(メールアドレス、ユーザー名、パスワード、氏名、住所、電話番号、oneTimeCode)を収集するすべての TextField に autofillHints を指定してください。AA で 1.3.5 を満たすために必須であり、A で 3.3.7「冗長な入力」に対応する基盤となります。
検出事項の形式 — 各監査の検出事項には、WCAG の基準 ID とその基準名(2.5.8 Target Size (Minimum) のように記載し、2.5.8 のみにはしません)、大文字で正確に CRITICAL、MAJOR、または MINOR のいずれかで表した重大度、および修正前後の Dart コードを含めます。重大度を High/Medium/Low や Serious/Moderate/Minor で評価してはいけません。修正内容が文章のみの検出事項を提示してはいけません。
非同期のお知らせ(WCAG 4.1.3)— ユーザーに表示される非同期の状態変化はすべて、Semantics(liveRegion: true) または SemanticsService.announce を介して通知する必要があります。
ワークフロー
アクセシビリティ対応はすべて、4 つのフェーズを順番に実施します。フェーズ 1 とフェーズ 2 は省略しないでください。
ホスト環境間の注意事項。 以下のフェーズ 1、2、4 では
AskUserQuestionを使用します。ホスト環境にこの機能がない場合は、ホストが提供する同等の質問ツールを呼び出してください。そのようなツールがない場合は、同じ質問を番号付きのテキストで尋ねてください。いずれの場合も、先に進む前に回答を待ってください。
フェーズ 1:適合レベルの選択
AskUserQuestion を使って、次の質問をします。
question: "Which WCAG 2.2 conformance level are you targeting?"
header: "WCAG level"
options:
- label: "A"
description: "Removes the most critical barriers. Includes the new 2.2 criteria 3.2.6 Consistent Help and 3.3.7 Redundant Entry."
- label: "AA"
description: "Standard most regulators require. Adds contrast, resize text, focus visible, plus the four new 2.2 AA criteria: 2.4.11, 2.5.7, 2.5.8, 3.3.8."
- label: "AA + selected AAA"
description: "AA across the app, plus specific AAA criteria scoped to flagged flows. Common: 1.4.6 enhanced contrast, 2.2.3 no timing, 2.4.13 focus appearance."
- label: "AAA"
description: "Full AAA. 7:1 contrast, no timing, no exceptions to keyboard. Rare for whole products."
ユーザーが「AA + selected AAA」を選んだ場合は、対象に含める AAA 基準 ID を自由記述で入力するよう追加で依頼します(例:「1.4.6, 2.2.3, 2.4.13」)。
結果: 選択されたレベルを記録します。すべての監査チェック、基準の引用、修正の推奨事項には、そのレベル(およびそれ以下のすべてのレベル)のルールと、対象に含めることを選択した AAA 基準のみを適用します。
フェーズ 2:プラットフォームの選択
AskUserQuestion を使って(利用できる場合は複数選択、利用できない場合はカンマ区切りで回答できる 1 つの質問を使って)、次の質問をします。
question: "Which platforms is this app targeting? Select all that apply."
header: "Platforms"
options:
- label: "iOS"
description: "VoiceOver, Switch Control, Dynamic Type up to 3.1x, Voice Control, Bold Text, Reduce Motion, Reduce Transparency."
- label: "Android"
description: "TalkBack, Switch Access, font scale up to 2x, Voice Access, color inversion."
- label: "Web"
description: "Flutter Web rendered to a Semantics-mapped DOM. NVDA + Chrome, JAWS + Chrome, VoiceOver + Safari."
- label: "macOS"
description: "VoiceOver, Full Keyboard Access, Reduce Motion, Increase Contrast."
- label: "Windows / Linux desktop"
description: "Narrator, NVDA, JAWS (Windows), Orca (Linux), Windows High Contrast Mode."
結果: 選択されたプラットフォームを記録します。references/platforms/ から該当するファイルを読み込みます(例:iOS の場合は references/platforms/ios.md、Android の場合は references/platforms/android.md)。選択されたプラットフォームのファイルのみを読み込み、不要なファイルは読み込まないでください。
フェーズ 3:適切なレベルとプラットフォームを考慮した監査
選択した各プラットフォームについて、提供されたファイルまたはウィジェットを、次の7つのカテゴリの順に監査します。
-
セマンティクスとスクリーンリーダー — ラベル、ロール、ライブリージョン、マージ/除外の適切さ、Cupertino のセマンティクスの不足、TalkBack と VoiceOver での読み上げ順序。
-
タッチターゲットとドラッグの代替手段 — AA での WCAG 2.2 2.5.8 の最小サイズ(24 CSS px)、AAA での 2.5.5 の拡張サイズ(44 CSS px)、VGV が推奨する 48 dp、および 2.5.7 のドラッグの代替手段。
-
フォーカスとキーボード操作 — 操作性、フォーカス移動順序、ダイアログのフォーカストラップ、フォーカスインジケーター、および 2.4.11/2.4.12 のフォーカスが隠れないこと。
-
色のコントラスト — 選択したレベルのしきい値(下表)におけるテキストと UI コンポーネントのコントラスト比。
-
テキストの拡大 — 高さが固定されたテキストコンテナーを使用しないこと、テキストの拡大を制限しないこと。シミュレーションの上限は Android と Web で 2x、iOS で 3x です。
-
アニメーションとモーション —
AnimationController、Hero、AnimatedContainer、PageRouteBuilder全体でのdisableAnimationsによる制御。AA では 3 Hz を超えるコンテンツの点滅を禁止し、AAA では点滅を一切禁止します。 -
フォーム、認証、ヘルプ —
autofillHints(1.3.5、3.3.7)、アクセシブルな認証(3.3.8/3.3.9)、ヘルプ手段の一貫した配置(3.2.6)。
選択したレベルで有効な基準(および選択した AAA 基準)のみを、選択したプラットフォームに関連する範囲で適用します。
すべての指摘を、行を省略せずにこのブロックに記載します。
### 1. Close button is a 16x16 GestureDetector
- **File:** lib/order/order_summary.dart ~L26
- **WCAG:** 2.1.1 Keyboard (Level A, WCAG 2.0)
- **Platform(s):** iOS, Android
- **Severity:** CRITICAL
- **Issue:** `GestureDetector` is pointer-only, so the close action is unreachable via VoiceOver, TalkBack, Switch Control, and Switch Access. Expected: a focusable, activatable button with an accessible name.
- **Fix:**
```dart
// Before
SizedBox(
width: 16,
height: 16,
child: GestureDetector(
onTap: onClose,
child: const Icon(Icons.close, size: 16),
),
)
```
```dart
// After
IconButton(
onPressed: onClose,
tooltip: 'Close order summary',
iconSize: 24,
constraints: const BoxConstraints(minWidth: 48, minHeight: 48),
icon: const Icon(Icons.close),
)
```
レポート内のすべての指摘(MINOR を含む)に適用されるルール:
- 基準。 ID と基準名をセットで記載し、その後にレベルと WCAG のバージョンを記載します:
2.5.8 Target Size (Minimum) (Level AA, WCAG 2.2)。番号だけでは指摘として不完全です。 - 重大度。
references/audit-templates.mdの重大度ガイドに従い、CRITICAL、MAJOR、MINOR のいずれか1つだけを記載します。プラットフォームによって異なる場合も、これら3つのラベルを使い、対象を明記します:CRITICAL (iOS, Android), MAJOR (Web)。 - 修正。 各指摘に、実際の Dart コードを使った Before ブロックと After ブロックを必ず並べて記載します。文章による助言だけでは修正にならず、After ブロックだけでも不十分です。読者が置き換えるコードを正確に確認できる必要があります。レポートの末尾に修正済みのウィジェットを1つまとめて記載しても、前述の指摘に対する要件を満たしません。
- 対象範囲。 チェックで問題が見つかっても、コードだけでは解決できない場合(色が分からない状態でのコントラスト、実行中のアプリがない状態での読み上げ順序など)は、指摘としてではなく「対象範囲外」に記載します。指摘は、根拠を示し、重大度を付け、修正できる内容に限ります。
成果物: 7つすべてのカテゴリを完了したら、references/audit-templates.md のテンプレートを使って監査レポートを作成します。フェーズ 1 に合った、レベル固有のチェック済み項目リストを選択します。
フェーズ 4:修正範囲の選択
レポートを提示した後、AskUserQuestion を使用します。
question: "The audit is complete. How would you like to proceed with fixes?"
header: "Fix scope"
options:
- label: "All issues"
description: "Fix every CRITICAL, MAJOR, and MINOR finding"
- label: "Critical + Major only"
description: "Fix blockers and significant barriers; skip MINOR polish items"
- label: "Critical only"
description: "Fix only what blocks assistive technology users entirely"
- label: "Specific findings"
description: "List the finding numbers you want fixed"
成果物: ユーザーが選択した修正だけを適用します。修正を適用した後、次のように確認します:「[N] 件の指摘([重大度])を修正しました。[N] 件が未対応のまま残っています。」
修正が再発しないよう、すべての修正を網羅するテストを作成します。7つすべての監査カテゴリを網羅したテストスイートについては references/testing.md を、特定のウィジェットに適した実装が不明な場合は references/widget-mapping.md を参照してください。
WCAG 2.2 レベル基準の参照資料
各レベルの基準表と、それぞれに対応する Flutter のチェック項目はこちらです:references/wcag-criteria.md。フェーズ 3 で読み込みます。
よくあるアンチパターンのクイックリファレンス
コードの完全なサンプルと修正版は references/examples.md にあります。以下は、このスキルが最も頻繁に指摘するパターンです。
セマンティクス(WCAG 1.1.1、4.1.2)
// WRONG: empty label, no label, ExcludeSemantics over actionable content removes the button
// from the semantics tree entirely, so the action is unreachable for screen reader users
Image.asset('assets/warning.png', semanticLabel: '')
Image.asset('assets/chart.png')
ExcludeSemantics(child: ElevatedButton(onPressed: _submit, child: const Text('Submit')))
// WRONG: Cupertino without semantic wrapper
CupertinoSwitch(value: _enabled, onChanged: _onChanged)
// WRONG: MergeSemantics around an interactive child folds the button's role away
MergeSemantics(
child: Row(children: [const Text('Item'), IconButton(onPressed: _delete, icon: ...)]),
)
タッチターゲットとドラッグ(WCAG 2.5.8、2.5.7)
// WRONG: 16x16 target, below WCAG 2.2 2.5.8 AA (24 dp)
SizedBox(width: 16, height: 16, child: GestureDetector(onTap: _onTap, child: const Icon(Icons.close, size: 16)))
// WRONG: Dismissible with no non-drag alternative (WCAG 2.2 2.5.7)
Dismissible(key: ValueKey(item.id), onDismissed: (_) => _delete(item), child: ListTile(title: Text(item.name)))
フォーカス(WCAG 2.1.1、2.4.11)
// WRONG: GestureDetector is not keyboard-accessible
GestureDetector(onTap: _onTap, child: const Text('Click me'))
// WRONG: bottom bar covers focused TextField (WCAG 2.2 2.4.11)
Scaffold(
resizeToAvoidBottomInset: false,
bottomNavigationBar: const BottomAppBar(child: ...),
body: ListView(children: [..., TextField(focusNode: _last), ...]),
)
テキストの拡大縮小と動き(WCAG 1.4.4、2.3.3)
// WRONG: clips text at 1.5x font scale
SizedBox(height: 48, child: Text('Status: Ready'))
// WRONG: animation always plays
AnimatedContainer(duration: const Duration(milliseconds: 500), color: ..., child: child)
修正済みのコードスニペット、クラス全体(AccessibleTapTarget、AccessibleSlider、AccessibleReorderableList、AccessiblePageRoute、AccessibleHero)、および Cupertino のセマンティックラッパーについては、references/examples.md をご覧ください。
追加リソース
references/wcag-criteria.md— 各レベルの WCAG 2.2 達成基準の表と、それぞれに対応する Flutter のチェック項目。references/audit-templates.md— 重大度ガイド、レポートのテンプレート、レベル別の合格チェックリスト、プラットフォーム横断の重大度表。references/examples.md— 各カテゴリの Flutter ウィジェットクラス全体。WCAG 2.2 のすべてのパターンを含みます。references/widget-mapping.md— よく監査される Flutter ウィジェットの、ウィジェットから要件へのクイックリファレンス。references/testing.md— 7 つの監査カテゴリすべてを対象にした、アクセシビリティテストスイートの完全な例。references/platforms/ios.md、android.md、web.md、macos.md、windows.md、linux.md— プラットフォームごとの WCAG 2.2 チェック項目と、Flutter 固有の注意事項。
公式リファレンス: