accessibility

Par verygoodopensource · vgv-ai-flutter-plugin

Auditez ou corrigez des widgets Flutter selon les niveaux de conformité d'accessibilité WCAG 2.2 A, AA ou AAA sur iOS, Android, Web, macOS, Windows et Linux.

npx skills add https://github.com/verygoodopensource/vgv-ai-flutter-plugin --skill accessibility

Accessibilité

Audit et correction d'accessibilité Flutter couvrant les niveaux de conformité WCAG 2.2 A, AA et AAA. Le skill est divisé en un workflow (ce fichier) plus des fichiers de référence chargés à la demande :

  • references/audit-templates.md — guide de sévérité, modèle de rapport, listes de vérifications réussies spécifiques aux niveaux A, AA, AA + AAA sélectionné, et AAA. Inclut également le tableau d'ajustement de sévérité multi-plateforme.
  • references/examples.md — code Flutter étendu par catégorie, y compris les modèles WCAG 2.2 (focus non obscurci, alternatives au dragage, wrappers sémantiques Cupertino, correction de MergeSemantics).
  • references/platforms/ios.md, android.md, web.md, macos.md, windows.md, linux.md — vérifications WCAG 2.2 par plateforme. Charger uniquement le(s) fichier(s) correspondant à la/aux plateforme(s) sélectionnée(s).

Lire le fichier de référence correspondant à la phase actuelle. Ne pas dupliquer son contenu ici.


Standards Fondamentaux

Appliquer ces standards à tous les travaux d'accessibilité :

Niveau de Conformité — Commencer chaque audit en demandant le niveau de conformité WCAG 2.2 que le projet vise (A, AA, AA + AAA sélectionné, ou AAA). Ne jamais supposer AA.

Sélection des Plateformes — Commencer chaque audit en demandant laquelle des six plateformes est ciblée (iOS, Android, Web, macOS, Windows, Linux). Appliquer les règles de plateforme du(des) fichier(s) correspondant(s) dans references/platforms/.

Sémantique des Images (WCAG 1.1.1) — Chaque Image doit avoir semanticLabel, ou être enveloppée dans Semantics(label:). Les images décoratives utilisent excludeFromSemantics: true.

Détecteur de Gestes (WCAG 2.1.1) — Ne jamais utiliser GestureDetector seul pour les cibles tactiles. Utiliser InkWell, ElevatedButton, TextButton, ou IconButton. GestureDetector est pointer-only et inaccessible via clavier ou accès par commutateur.

Taille de Cible (WCAG 2.5.8) — La taille minimale de cible est 24x24 CSS px (≈ 24 dp) en AA. Le minimum recommandé par VGV est 48x48 dp. Les résultats entre 24 dp et 48 dp sont signalés comme style VGV en AA, et comme des résultats WCAG en AAA via 2.5.5 (44 dp).

Alternatives au Dragage (WCAG 2.5.7) — Chaque fonction basée sur le dragage doit offrir une alternative sans dragage sur le même écran. Les curseurs ont besoin d'alternatives clavier ou pas à pas. Dismissible a besoin d'un bouton de suppression explicite. ReorderableListView a besoin de contrôles vers le haut/bas ou « déplacer vers ».

Focus Non Obscurci (WCAG 2.4.11) — Un widget en focus ne doit pas être entièrement obscurci par les en-têtes fixes, snackbars, bottom sheets, FABs persistants, ou overlays. Utiliser Scrollable.ensureVisible et Scaffold.resizeToAvoidBottomInset: true.

Différenciation de Couleur (WCAG 1.4.1) — Ne jamais utiliser la couleur comme seul différenciateur. Toujours associer la couleur à un label, icône ou forme.

Animation et Mouvement (WCAG 2.3.3) — Toutes les animations doivent respecter MediaQuery.disableAnimations. Gater chaque AnimationController, AnimatedContainer, transition Hero, et transition PageRouteBuilder sur ce flag.

Boutons Icône (WCAG 4.1.2) — Les boutons icône-seul doivent avoir un Tooltip ou Semantics(label:). Les lecteurs d'écran n'ont aucun autre moyen de communiquer l'objectif.

Exclure la Sémantique (WCAG 1.1.1) — Ne jamais utiliser ExcludeSemantics sur du contenu non-décoratif.

Conteneurs de Texte (WCAG 1.4.4) — Les conteneurs à hauteur fixe ne doivent pas envelopper Text. Utiliser des contraintes minHeight. Les hauteurs fixes coupent le texte à l'échelle 1,5x sur Android, plus tôt sur iOS où les Larger Accessibility Sizes vont jusqu'à ~3,1x.

Contraste (WCAG 1.4.3) — Tout texte et composant UI doit respecter le ratio de contraste du niveau WCAG sélectionné. Voir la section Référence des Critères de Niveau WCAG ci-dessous.

Sémantique Cupertino (WCAG 4.1.2) — Les widgets Cupertino (CupertinoSwitch, CupertinoSlider, CupertinoSegmentedControl, CupertinoButton) ont des défauts sémantiques plus faibles que leurs équivalents Material. Toujours les envelopper dans Semantics(label:, value:, button:).

Indices de Remplissage Automatique (WCAG 1.3.5) — Chaque TextField collectant des données personnelles structurées (e-mail, identifiant utilisateur, mot de passe, nom, adresse, téléphone, oneTimeCode) doit déclarer autofillHints. Requis pour 1.3.5 en AA et la base pour 3.3.7 Redundant Entry en A.

Annonces Asynchrones (WCAG 4.1.3) — Chaque changement d'état asynchrone visible par l'utilisateur doit s'annoncer via Semantics(liveRegion: true) ou SemanticsService.announce.


Workflow

Chaque engagement d'accessibilité suit quatre phases en séquence. Ne pas sauter la Phase 1 ou la Phase 2.

Phase 1 : Sélection du Niveau de Conformité

Utiliser AskUserQuestion pour demander :

question: "Quel niveau de conformité WCAG 2.2 visez-vous ?"
header: "Niveau WCAG"
options:
  - label: "A"
    description: "Supprime les barrières les plus critiques. Inclut les nouveaux critères 2.2 3.2.6 Consistent Help et 3.3.7 Redundant Entry."
  - label: "AA"
    description: "Standard que la plupart des régulateurs exigent. Ajoute le contraste, redimensionnement du texte, focus visible, plus les quatre nouveaux critères AA 2.2 : 2.4.11, 2.5.7, 2.5.8, 3.3.8."
  - label: "AA + AAA sélectionné"
    description: "AA dans toute l'application, plus des critères AAA spécifiques limités aux flux signalés. Courant : 1.4.6 contraste renforcé, 2.2.3 sans limitation de temps, 2.4.13 apparence du focus."
  - label: "AAA"
    description: "AAA complet. Contraste 7:1, sans limitation de temps, pas d'exceptions au clavier. Rare pour les produits entiers."

Si l'utilisateur choisit « AA + AAA sélectionné », faire un suivi avec une requête texte libre pour les IDs de critères AAA qu'il souhaite inclure (par exemple, « 1.4.6, 2.2.3, 2.4.13 »).

Résultat : Enregistrer le niveau sélectionné. Tous les vérifications d'audit, citations de critères et recommandations de correction s'appliquent uniquement aux règles de ce niveau (plus tous les niveaux en dessous) et aux critères AAA acceptés.

Phase 2 : Sélection des Plateformes

Utiliser AskUserQuestion (multi-sélection si disponible, sinon une question avec réponse séparée par des virgules) pour demander :

question: "Quelles plateformes cette application cible-t-elle ? Sélectionner toutes les options applicables."
header: "Plateformes"
options:
  - label: "iOS"
    description: "VoiceOver, Switch Control, Dynamic Type jusqu'à 3,1x, Voice Control, Bold Text, Reduce Motion, Reduce Transparency."
  - label: "Android"
    description: "TalkBack, Switch Access, échelle de police jusqu'à 2x, Voice Access, inversion des couleurs."
  - label: "Web"
    description: "Flutter Web rendu à un DOM mappé Semantics. 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."

Résultat : Enregistrer les plateformes sélectionnées. Charger le(s) fichier(s) correspondant(s) depuis references/platforms/ (par exemple, references/platforms/ios.md pour iOS, references/platforms/android.md pour Android). Charger uniquement les fichiers pour les plateformes sélectionnées ; ne pas charger de fichiers inutiles.

Phase 3 : Audit Adapté au Niveau et à la Plateforme

Pour chaque plateforme sélectionnée, auditer les fichiers ou widgets fournis dans sept catégories, dans l'ordre :

  1. Sémantique et Lecteur d'Écran — Labels, rôles, régions actives, correction merge/exclude, lacunes sémantiques Cupertino, ordre de lecture sous TalkBack et VoiceOver.

  2. Cibles Tactiles et Alternatives au Dragage — Minimum WCAG 2.2 2.5.8 (24 CSS px) en AA, amélioré 2.5.5 (44 CSS px) en AAA, VGV recommandé 48 dp, plus alternatives 2.5.7 au dragage.

  3. Navigation au Focus et au Clavier — Opérabilité, ordre de traversée, piégeage du focus dans les dialogs, indicateurs de focus, plus 2.4.11 / 2.4.12 focus non obscurci.

  4. Contraste de Couleur — Ratios texte et composant UI au seuil du niveau sélectionné (tableau ci-dessous).

  5. Mise à l'Échelle du Texte — Aucun conteneur de texte à hauteur fixe, aucune mise à l'échelle du texte fixée. Limiter les simulations à 2x sur Android et Web, 3x sur iOS.

  6. Animation et Mouvement — Gating disableAnimations sur AnimationController, Hero, AnimatedContainer, PageRouteBuilder. Aucun contenu clignotant au-dessus de 3 Hz en AA, zéro clignotement en AAA.

  7. Formulaires, Authentification et AideautofillHints (1.3.5, 3.3.7), authentification accessible (3.3.8 / 3.3.9), placement cohérent des mécanismes d'aide (3.2.6).

Appliquer uniquement les critères actifs au niveau sélectionné (plus AAA accepté) et pertinents pour les plateformes sélectionnées.

Pour chaque résultat, capturer : chemin de fichier et numéro de ligne approximatif, ID de critère WCAG + nom + version (2.0 / 2.1 / 2.2), plateforme(s) affectée(s), sévérité (CRITIQUE / MAJEURE / MINEURE), comportement actuel, comportement attendu, correction Flutter sous forme de diff avant-après.

Résultat : Après completion de toutes les sept catégories, produire le Rapport d'Audit en utilisant le modèle dans references/audit-templates.md. Choisir la liste de vérifications réussies spécifique au niveau qui correspond à la Phase 1.

Phase 4 : Sélection de l'Étendue de Correction

Après livraison du rapport, utiliser AskUserQuestion :

question: "L'audit est terminé. Comment souhaitez-vous procéder pour les corrections ?"
header: "Étendue des corrections"
options:
  - label: "Tous les problèmes"
    description: "Corriger tous les résultats CRITIQUE, MAJEURE et MINEURE"
  - label: "Critique + Majeure seulement"
    description: "Corriger les blocages et barrières significatives ; ignorer les éléments de polissage MINEURE"
  - label: "Critique seulement"
    description: "Corriger uniquement ce qui bloque complètement les utilisateurs de technologie d'assistance"
  - label: "Résultats spécifiques"
    description: "Lister les numéros de résultats que vous souhaitez corriger"

Résultat : Appliquer exactement les corrections que l'utilisateur sélectionne. Après application des corrections, confirmer : « [N] résultats corrigés ([sévérités]). [N restants] restent ouverts. »


Référence des Critères du Niveau WCAG 2.2

Le niveau AA inclut tous les critères du niveau A. Le niveau AAA inclut tous les critères des niveaux A et AA. La colonne « Version » signale si le critère provient de WCAG 2.0, 2.1 ou 2.2. WCAG 2.2 a supprimé 4.1.1 Parsing.

Niveau A

ID WCAG Version Critère Vérification Flutter
1.1.1 2.0 Contenu Non-Texte semanticLabel sur les images, Semantics(label:) sur les icônes, excludeFromSemantics: true sur les éléments décoratifs
1.3.1 2.0 Info et Relations Rôles sémantiques. MergeSemantics pour paires label/valeur groupées seulement, jamais autour d'enfants interactifs
1.3.2 2.0 Séquence Significative L'ordre de lecture correspond à l'ordre visuel. FocusTraversalGroup + OrderedTraversalPolicy
1.3.3 2.0 Caractéristiques Sensorielles Les instructions ne dépendent pas uniquement de la forme, taille, localisation ou son
1.4.1 2.0 Utilisation de la Couleur La couleur ne doit jamais être le seul différenciateur
2.1.1 2.0 Clavier Toute fonctionnalité via clavier ou accès par commutateur. Pas de GestureDetector seul
2.1.2 2.0 Pas de Piège au Clavier Le focus peut toujours être déplacé
2.3.1 2.0 Trois Clignotements ou Sous le Seuil Aucun contenu ne clignote > 3 fois par seconde
2.4.1 2.0 Contourner les Blocs Mécanisme de navigation rapide. Web uniquement
2.4.2 2.0 Page Titrée Chaque écran a un titre significatif. Web : balise <title>
2.4.3 2.0 Ordre du Focus L'ordre Tab/focus préserve le sens
2.5.3 2.1 Label dans le Nom Le texte du label visible est contenu dans le nom accessible
3.2.6 2.2 Aide Cohérente Mécanisme d'aide dans le même ordre relatif sur les écrans
3.3.1 2.0 Identification des Erreurs Les erreurs de formulaire sont identifiées en texte, pas seulement par couleur
3.3.2 2.0 Labels ou Instructions Tous les champs de formulaire ont des labels visibles
3.3.7 2.2 Entrée Redondante Les formulaires multi-étapes ne doivent pas re-collecter les informations déjà fournies sauf si la re-saisie est essentielle
4.1.2 2.0 Nom, Rôle, Valeur Semantics(label:, button: true), Tooltip, état via checked, selected, enabled
4.1.3 2.1 Messages de Statut Semantics(liveRegion: true), SemanticsService.announce()

Niveau AA (ajoute ceux-ci au Niveau A)

ID WCAG Version Critère Vérification Flutter
1.3.4 2.1 Orientation L'application n'est pas verrouillée à une seule orientation sans raison essentielle
1.3.5 2.1 Identifier l'Objectif de l'Entrée Correct keyboardType et autofillHints
1.4.3 2.0 Contraste (Minimum) Texte normal 4,5:1, texte large 3:1
1.4.4 2.0 Redimensionner le Texte Le texte s'adapte à 200% (300% sur iOS) sans perte
1.4.5 2.0 Images de Texte Utiliser Text, pas d'images de texte
1.4.10 2.1 Reflux Le contenu se refondre à l'équivalent 320 CSS px
1.4.11 2.1 Contraste Non-Texte Composants UI et indicateurs de focus 3:1
1.4.12 2.1 Espacement du Texte Le contenu n'est pas perdu sous l'espacement augmenté
1.4.13 2.1 Contenu au Survol ou au Focus Masquable, survolable, persistant. Web/desktop
2.4.5 2.0 Plusieurs Moyens Plus d'une façon de localiser un écran
2.4.6 2.0 En-têtes et Labels Descriptifs. Semantics(header: true) pour les sections
2.4.7 2.0 Focus Visible L'indicateur de focus clavier est toujours visible
2.4.11 2.2 Focus Non Obscurci (Minimum) Le composant en focus n'est pas entièrement caché par le contenu créé par l'auteur
2.5.7 2.2 Mouvements de Dragage Chaque dragage a une alternative mono-pointeur
2.5.8 2.2 Taille de Cible (Minimum) Les cibles >= 24x24 CSS px, avec exceptions documentées
3.1.2 2.0 Langue des Parties Web : attribut lang
3.2.3 2.0 Navigation Cohérente Cohérente sur les écrans
3.2.4 2.0 Identification Cohérente Les composants avec la même fonction sont identifiés de manière cohérente
3.3.3 2.0 Suggestion d'Erreur Correction suggérée quand possible
3.3.4 2.0 Prévention des Erreurs (Légal/Financier) Réversible ou confirmable
3.3.8 2.2 Authentification Accessible (Minimum) Aucun test de fonction cognitive requis sans alternative. Permettre le collage, soutenir les gestionnaires de mots de passe, pas de CAPTCHA puzzle sans alternative

Niveau AAA (ajoute ceux-ci aux niveaux A et AA)

ID WCAG Version Critère Vérification Flutter
1.4.6 2.0 Contraste (Renforcé) Normal 7:1, large 4,5:1
2.1.3 2.0 Clavier (Aucune Exception) Pas de GestureDetector nulle part
2.2.3 2.0 Pas de Limitation de Temps Aucune limite de temps sauf événements temps réel
2.2.6 2.1 Délais d'Inactivité Avertissement d'inactivité
2.3.2 2.0 Trois Clignotements Zéro clignotement
2.3.3 2.1 Animation à partir des Interactions Chaque animation dépend de disableAnimations
2.4.8 2.0 Localisation Les utilisateurs savent toujours où ils sont
2.4.9 2.0 Objectif du Lien (Lien Uniquement) Compréhensible par le seul texte du lien
2.4.12 2.2 Focus Non Obscurci (Amélioré) Aucune occlusion du tout, pas seulement occlusion totale
2.4.13 2.2 Apparence du Focus Au moins 2 CSS px de périmètre, entoure le composant, 3:1 contre non-focus
2.5.5 2.1 Taille de Cible (Amélioré) Les cibles >= 44x44 CSS px
2.5.6 2.1 Mécanismes d'Entrée Concurrents Aucune restriction à modalité unique
3.2.5 2.0 Changement sur Demande Les changements de contexte uniquement sur demande de l'utilisateur
3.3.5 2.0 Aide Aide contextuelle disponible
3.3.6 2.0 Prévention des Erreurs (Toutes) Tous les envois réversibles ou confirmables
3.3.9 2.2 Authentification Accessible (Amélioré) Aucun test de fonction cognitive même avec alternative

Référence Rapide des Anti-Modèles

Les exemples de code complets et les versions corrigées se trouvent dans references/examples.md. Les modèles ci-dessous sont ceux que le skill signale le plus souvent.

Sémantique (WCAG 1.1.1, 4.1.2)

// MAUVAIS : label vide, pas de label, ExcludeSemantics sur actionnable
Image.asset('assets/warning.png', semanticLabel: '')
Image.asset('assets/chart.png')
ExcludeSemantics(child: ElevatedButton(onPressed: _submit, child: const Text('Submit')))
// MAUVAIS : Cupertino sans wrapper sémantique
CupertinoSwitch(value: _enabled, onChanged: _onChanged)
// MAUVAIS : MergeSemantics autour d'un enfant interactif plie le rôle du bouton
MergeSemantics(
  child: Row(children: [const Text('Item'), IconButton(onPressed: _delete, icon: ...)]),
)

Cibles Tactiles et Dragage (WCAG 2.5.8, 2.5.7)

// MAUVAIS : cible 16x16, en dessous du 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)))
// MAUVAIS : Dismissible sans alternative non-dragage (WCAG 2.2 2.5.7)
Dismissible(key: ValueKey(item.id), onDismissed: (_) => _delete(item), child: ListTile(title: Text(item.name)))

Focus (WCAG 2.1.1, 2.4.11)

// MAUVAIS : GestureDetector n'est pas accessible au clavier
GestureDetector(onTap: _onTap, child: const Text('Click me'))
// MAUVAIS : barre inférieure couvre TextField en focus (WCAG 2.2 2.4.11)
Scaffold(
  resizeToAvoidBottomInset: false,
  bottomNavigationBar: const BottomAppBar(child: ...),
  body: ListView(children: [..., TextField(focusNode: _last), ...]),
)

Mise à l'Échelle du Texte et Mouvement (WCAG 1.4.4, 2.3.3)

// MAUVAIS : coupe le texte à l'échelle 1,5x
SizedBox(height: 48, child: Text('Status: Ready'))
// MAUVAIS : l'animation joue toujours
AnimatedContainer(duration: const Duration(milliseconds: 500), color: ..., child: child)

Pour les snippets corrigés, les classes complètes (AccessibleTapTarget, AccessibleSlider, AccessibleReorderableList, AccessiblePageRoute, AccessibleHero), et les wrappers sémantiques Cupertino, voir references/examples.md.


Ressources Supplémentaires

Références officielles :

Skills similaires