flutter-accessibility-audit

Par flutter · skills

Déclenche un scan d'accessibilité via le widget_inspector et ajoute automatiquement des widgets Semantics ou des labels manquants au code source.

npx skills add https://github.com/flutter/skills --skill flutter-accessibility-audit

Implémentation de l'accessibilité Flutter

Sommaire

Gérer la sémantique

Appuyez-vous sur les widgets standard de Flutter (par exemple TabBar, MenuAnchor) pour l'attribution automatique des rôles sémantiques chaque fois que possible. Lors de la création de composants personnalisés ou de la modification des comportements par défaut, définissez explicitement le rôle du composant UI à l'aide du widget Semantics.

  • Enveloppez les composants UI personnalisés dans un widget Semantics.
  • Attribuez la valeur enum SemanticsRole appropriée à la propriété role pour définir le rôle de l'élément (par exemple, button, list, heading).
  • Si vous ciblez Flutter Web, notez que Flutter traduit ces rôles en rôles ARIA correspondants dans le DOM HTML.
  • Activez explicitement l'accessibilité web. Elle est désactivée par défaut pour des raisons de performance. Demandez à vos utilisateurs d'appuyer sur le bouton invisible aria-label="Enable accessibility", ou forcez-la programmatiquement dans votre fonction main().

Auditer l'accessibilité

Mettez en œuvre les workflows suivants pour vérifier que votre application respecte les normes d'accessibilité.

Progression des tâches : analyse spécifique à la plateforme

Copiez cette checklist pour suivre votre progression d'audit manuel sur les plateformes cibles :

  • [ ] Si vous testez sur Android :
    1. Installez Accessibility Scanner depuis Google Play.
    2. Activez-le via Paramètres > Accessibilité > Accessibility Scanner > Activé.
    3. Appuyez sur l'icône de coche d'Accessibility Scanner au-dessus de votre application en cours d'exécution pour lancer l'analyse.
  • [ ] Si vous testez sur iOS :
    1. Ouvrez le dossier ios dans Xcode et exécutez l'application sur un simulateur.
    2. Accédez à Xcode > Open Developer Tools > Accessibility Inspector.
    3. Sélectionnez Inspection > Enable Point to Inspect et cliquez sur les éléments UI pour vérifier les attributs.
    4. Sélectionnez Audit > Run Audit pour générer un rapport de problèmes.
  • [ ] Si vous testez sur Web :
    1. Ouvrez Chrome DevTools.
    2. Inspectez l'arbre HTML sous le nœud semantics host.
    3. Accédez à l'onglet Elements et ouvrez le sous-onglet Accessibility pour inspecter les données ARIA exportées.
    4. Visualisez les nœuds sémantiques en exécutant l'application avec : flutter run -d chrome --profile --dart-define=FLUTTER_WEB_DEBUG_SHOW_SEMANTICS=true.

Progression des tâches : tests automatisés

Intégrez l'API Accessibility Guideline de Flutter dans vos tests de widgets pour détecter automatiquement les problèmes de contraste, de taille de cible et d'étiquetage.

  • [ ] Créez un fichier de test dédié (par exemple, test/a11y_test.dart).
  • [ ] Initialisez la poignée sémantique en utilisant tester.ensureSemantics().
  • [ ] Assertez avec androidTapTargetGuideline (minimum 48x48px).
  • [ ] Assertez avec iOSTapTargetGuideline (minimum 44x44px).
  • [ ] Assertez avec labeledTapTargetGuideline.
  • [ ] Assertez avec textContrastGuideline (minimum 3:1 pour le texte grand).
  • [ ] Libérez la poignée sémantique à la fin du test.

Déboguer l'arbre sémantique

Quand les nœuds sémantiques sont mal placés ou manquants, exécutez la boucle de rétroaction suivante pour identifier et résoudre les divergences.

  1. Exécutez le validateur : déclenchez un dump de l'arbre Semantics dans la console.
    • Activez l'accessibilité via un outil système ou SemanticsDebugger.
    • Invoquez debugDumpSemanticsTree() (par exemple, liez-le au callback onTap d'un GestureDetector pour un déclenchement facile lors du débogage).
  2. Examinez les erreurs : analysez la sortie de la console pour localiser les étiquettes manquantes, les rôles incorrects ou les nœuds sémantiques mal imbriqués.
  3. Corrigez : enveloppez les widgets problématiques dans des widgets Semantics ou MergeSemantics, appliquez le SemanticsRole correct et répétez l'étape 1 jusqu'à ce que l'arbre reflète exactement l'interface utilisateur visuelle.

Exemples

Activation programmatique de l'accessibilité Web

Forcez l'arbre Semantics à se construire immédiatement sur Flutter Web.

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/semantics.dart';

void main() {
  runApp(const MyApp());
  if (kIsWeb) {
    SemanticsBinding.instance.ensureSemantics();
  }
}

Définition explicite des rôles sémantiques

Attribuez des rôles list et list-item explicites à une mise en page personnalisée.

import 'package:flutter/material.dart';
import 'package:flutter/semantics.dart';

class MyCustomListWidget extends StatelessWidget {
  const MyCustomListWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Semantics(
      role: SemanticsRole.list,
      explicitChildNodes: true,
      child: Column(
        children: <Widget>[
          Semantics(
            role: SemanticsRole.listItem,
            child: const Padding(
              padding: EdgeInsets.all(8.0),
              child: Text('Content of the first custom list item.'),
            ),
          ),
          Semantics(
            role: SemanticsRole.listItem,
            child: const Padding(
              padding: EdgeInsets.all(8.0),
              child: Text('Content of the second custom list item.'),
            ),
          ),
        ],
      ),
    );
  }
}

Tests d'accessibilité automatisés

Implémentez l'API Accessibility Guideline dans un test de widget.

import 'package:flutter_test/flutter_test.dart';
import 'package:your_accessible_app/main.dart';

void main() {
  testWidgets('Follows a11y guidelines', (tester) async {
    final SemanticsHandle handle = tester.ensureSemantics();
    await tester.pumpWidget(const AccessibleApp());

    // Check tap target sizes
    await expectLater(tester, meetsGuideline(androidTapTargetGuideline));
    await expectLater(tester, meetsGuideline(iOSTapTargetGuideline));

    // Check labels and contrast
    await expectLater(tester, meetsGuideline(labeledTapTargetGuideline));
    await expectLater(tester, meetsGuideline(textContrastGuideline));

    handle.dispose();
  });
}

Skills similaires