Accessibility Trait : essence, types et fonctionnement dans le développement

Auteur : IT Sectr Publié le : 2026-05-16 Temps de lecture : 9 min

Accessibility Trait est une propriété d'élément iOS qui détermine son rôle et son comportement pour VoiceOver. Le trait indique au lecteur d'écran comment l'élément doit être annoncé et quels gestes sont disponibles : s'il s'agit d'un bouton, d'un en-tête, d'un lien ou d'un champ de recherche. Selon Apple UIAccessibilityTraits, 2024, le système prend en charge plus de 15 constantes qui peuvent être combinées à l'aide d'un masque de bits. Un trait correctement choisi économise jusqu'à 50% du temps de navigation pour les utilisateurs de VoiceOver.

Points Clés

  • Accessibility Trait — le rôle d'un élément iOS pour VoiceOver ; défini via les constantes UIAccessibilityTraits
  • Les traits peuvent être combinés à l'aide de l'opérateur | pour créer des rôles complexes (bouton + sélectionné)
  • Chaque élément peut avoir plusieurs traits simultanément, mais pas plus de 3-4 pour éviter toute confusion
  • Un trait incorrect (par exemple, StaticText pour un bouton) brise le scénario d'interaction : l'utilisateur ne sait pas si un geste est disponible
  • Sur Android, l'équivalent est les attributs role et className dans AccessibilityNodeInfo

Qu'est-ce qu'Accessibility Trait

Accessibility Trait est un indicateur défini sur un élément UIView pour indiquer son rôle sémantique à VoiceOver. Le trait est l'un des trois composants de la triade d'accessibilité d'Apple : Label (nom), Hint (description), Trait (rôle). iOS utilise le masque de bits UIAccessibilityTraits (UInt64), où chaque bit correspond à un rôle spécifique. VoiceOver lit le rôle après Label et Hint : « Bouton Envoyer. Ouvrira un formulaire » — « Bouton » est ajouté grâce au trait UIAccessibilityTraitButton.

Par défaut, UIButton reçoit UIAccessibilityTraitButton, UILabel reçoit UIAccessibilityTraitStaticText, UIImageView reçoit UIAccessibilityTraitImage. Lors de l'utilisation de contrôles personnalisés, le développeur doit définir le trait manuellement. Apple Human Interface Guidelines, 2024, appellent cela « l'une des étapes les plus critiques pour garantir l'accessibilité ».

Sans le bon trait, l'utilisateur ne sait pas quel geste appliquer : tap simple (activation du bouton), double tap (zoom) ou geste de balayage (interrupteur). Le trait détermine quels gestes VoiceOver sont activés sur l'élément.

Implémentation technique de UIAccessibilityTraits

UIAccessibilityTraits est un typealias UInt64. Chaque trait est une constante avec exactement un bit défini. Par exemple, UIAccessibilityTraitButton = 0x0000000000000001, UIAccessibilityTraitLink = 0x0000000000000002, UIAccessibilityTraitHeader = 0x0000000000000008. Les combinaisons sont réalisées avec un OU binaire : 0x0001 | 0x0008 = 0x0009. VoiceOver analyse le masque et détermine le comportement.

Principaux types de traits iOS

iOS fournit plus de 15 constantes de traits. Examinons les principales utilisées dans 90% des scénarios :

TraitConstanteComportement VoiceOver
ButtonUIAccessibilityTraitButtonActivation par double tap
HeaderUIAccessibilityTraitHeaderNavigation rapide par en-têtes
LinkUIAccessibilityTraitLinkActivation comme lien
StaticTextUIAccessibilityTraitStaticTextLecture seule, sans activation
SearchFieldUIAccessibilityTraitSearchFieldChamp de recherche avec comportement spécial
ImageUIAccessibilityTraitImageImage, sans geste d'activation
SelectedUIAccessibilityTraitSelectedÉtat « sélectionné »
PlaysSoundUIAccessibilityTraitPlaysSoundJoue un son à l'activation
KeyboardKeyUIAccessibilityTraitKeyboardKeyTouche de clavier
TabBarUIAccessibilityTraitTabBarÉlément de barre d'onglets

Les constantes sont disponibles dans UIKit depuis iOS 3.0. iOS 14+ a ajouté la prise en charge de UIAccessibilityTraits dans SwiftUI via le modificateur .accessibilityAddTraits().

Traits rares mais utiles

UIAccessibilityTraitAdjustable — pour les valeurs ajustables (curseurs, sélecteurs, contrôles de volume). VoiceOver permet de balayer vers le haut/bas pour modifier la valeur avec un pas défini via accessibilityIncrement et accessibilityDecrement. UIAccessibilityTraitUpdatesFrequently — pour les éléments avec des valeurs changeant fréquemment (minuteur, indicateur de progression). VoiceOver ne lit pas la valeur à chaque changement mais fait une pause. UIAccessibilityTraitAllowsDirectInteraction — pour les éléments avec lesquels l'utilisateur peut interagir directement (clavier, dessin), en contournant les gestes VoiceOver.

Combinaison de traits

Un seul élément peut avoir plusieurs traits simultanément — la combinaison est définie à l'aide du OU binaire (|). Exemple : un bouton actuellement sélectionné — Button | Selected. VoiceOver annoncera : « Sélectionné. Filtré par prix. Bouton. »

Définition des traits dans le code :

swift
filterButton.accessibilityTraits.insert(.button)
filterButton.accessibilityTraits.insert(.selected)

// Ou via un masque :
filterButton.accessibilityTraits = [.button, .selected]

Pour UIView personnalisé où le trait n'est pas défini par défaut :

swift
class CustomToggle: UIControl {
    override var accessibilityTraits: UIAccessibilityTraits {
        get {
            if isOn {
                return [.button, .selected]
            } else {
                return .button
            }
        }
        set {}
    }
}

Règle de combinaison : pas plus de 3-4 traits par élément. Des traits excessifs (par exemple, Button + Link + Header) rendent l'annonce VoiceOver trop longue et confuse. Selon Apple, « chaque propriété supplémentaire augmente la charge cognitive de l'utilisateur ».

SwiftUI : Modificateurs de traits

Dans SwiftUI, les traits sont définis à l'aide des modificateurs .accessibilityAddTraits() et .accessibilityRemoveTraits(). Exemple : Text(« Titre »).font(.largeTitle).accessibilityAddTraits(.isHeader). Le modificateur .isHeader ajoute UIAccessibilityTraitHeader. Liste des traits SwiftUI : .isButton, .isHeader, .isLink, .isSelected, .isImage, .isSearchField, .isKeyboardKey, .isStaticText, .isSummaryElement, .isToggle, .playsSound, .startsMediaSession, .updatesFrequently, .allowsDirectInteraction, .causesPageTurn, .isModal, .tabBar.

Erreurs typiques dans le choix d'un trait

StaticText au lieu de Button — un contrôle personnalisé qui ressemble visuellement à un bouton reçoit le trait StaticText par défaut. VoiceOver n'offre pas de geste d'activation, donc l'utilisateur ne peut pas « appuyer » sur l'élément. Solution : définir explicitement .button.

Image sans trait — UIImageView avec accessibilité activée reçoit le trait Image, même s'il s'agit en réalité d'un bouton pour agrandir une photo. Attribuez .button et Label « Agrandir la photo ». Selon WWDC 2023, « Deliver an Exceptional Accessibility Experience », 40% des régressions d'accessibilité dans les nouvelles versions d'applications sont causées précisément par l'inadéquation du trait.

Header sur chaque élément — le trait Header est destiné aux en-têtes structurels de l'écran. Si chaque UILabel devient un en-tête, le rotor VoiceOver en mode « En-têtes » devient inutile — il s'arrêtera sur chaque mot.

Comment corriger : liste de vérification

  • Chaque élément personnalisé interactif reçoit le trait Button, Link ou Adjustable
  • Les en-têtes de section reçoivent le trait Header (pas StaticText)
  • Les boutons d'image reçoivent le trait Button + Selected à l'état sélectionné
  • Éléments sans geste — StaticText ou Image (lecture seule)

Bugs de régression lors du remplacement de UIButton par UIControl

Une cause fréquente de perte de trait est le refactoring : un développeur remplace UIButton par UIControl pour un affichage personnalisé. UIButton reçoit automatiquement le trait Button, UIControl non. Après le refactoring, vous devez définir explicitement accessibilityTraits = .button. Ajoutez une vérification dans la revue de code : « Si vous avez remplacé UIButton par UIControl — vérifiez le trait. »

Traits et états dynamiques

Pour les éléments avec un état changeant (par exemple, un bouton J'aime), le trait doit changer dynamiquement. À l'état « non aimé » — Button, à l'état « aimé » — Button + Selected + Image (s'il y a une icône). VoiceOver change l'annonce : « J'aime. Bouton. » vs « Sélectionné. J'aime. Bouton. » Utilisez accessibilityValue pour transmettre l'état si le trait Selected est insuffisant. Pertinent pour les boutons d'abonnement, favoris, filtres et interrupteurs.

Équivalent Android : role et className

Sur Android, il n'y a pas d'équivalent direct aux traits. Au lieu d'un masque de bits, on utilise :

  • className — la valeur de AccessibilityNodeInfo.className (android.widget.Button, android.widget.TextView)
  • role — un attribut XML (le rôle est déterminé par le type de View)
  • stateDescription — un équivalent de Selected : ajout d'une description d'état (activé/désactivé)

Pour les Views personnalisés sur Android, vous devez redéfinir onInitializeAccessibilityNodeInfo :

kotlin
class CustomButton @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null
) : View(context, attrs) {

    override fun onInitializeAccessibilityNodeInfo(
        info: AccessibilityNodeInfo
    ) {
        super.onInitializeAccessibilityNodeInfo(info)
        info.className = "android.widget.Button"
        info.isClickable = true
    }
}

Les développeurs Flutter doivent utiliser le paramètre semanticsRole dans le widget Semantics : button, header, image, link, textField et autres. De plus, semanticsLabel et semanticsHint sont disponibles — un équivalent complet de la triade iOS Label + Hint + Trait.

Équivalents web : rôle WAI-ARIA

Pour les versions web des applications mobiles (PWA, WebView), l'attribut role de WAI-ARIA est utilisé : role="button", role="heading", role="link". C'est un équivalent direct de accessibilityTraits. Dans les applications hybrides, vérifiez que WebView transmet les rôles ARIA à la couche d'accessibilité native. Pour cela, utilisez le protocole UIAccessibilityContainerDataTable sur iOS ou setAccessibilityDelegate sur Android. Un WebView avec JavaScript activé peut ne pas transmettre correctement les rôles ARIA — testez séparément.

AccessibilityNodeInfo : Actions supplémentaires

Sur Android, vous pouvez ajouter des actions personnalisées à AccessibilityNodeInfo : AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK et ACTION_LONG_CLICK. Cela équivaut au trait Button avec des gestes supplémentaires. Pour les curseurs, utilisez ACTION_SET_PROGRESS — équivalent de Adjustable. Pour Spinner et DatePicker — ACTION_SET_SELECTION, ACTION_SET_DATE et ACTION_SET_TIME.

Vérification et test des traits

Xcode Accessibility Inspector est l'outil principal pour iOS : sélectionnez un élément et consultez le champ Traits. Il affichera la liste des traits définis. Le rotor VoiceOver avec le mode « Éléments » permet de naviguer à travers tous les contrôles de l'écran.

Test automatisé en Swift pour vérifier un trait :

swift
func testSubmitButtonTrait() {
    let app = XCUIApplication()
    app.launch()
    let submitButton = app.buttons["Envoyer"]
    XCTAssertTrue(submitButton.isEnabled)
    // XCUIElement ne fournit pas d'accès direct aux traits
    // Vérification via l'activation du geste
    submitButton.tap()
    XCTAssertTrue(app.staticTexts["Formulaire envoyé"].exists)
}

Vérification manuelle via VoiceOver : activez VoiceOver, balayez jusqu'à l'élément, tapez deux fois — l'élément doit s'activer s'il s'agit d'un Button. Si l'élément ne répond pas au double tap, le trait est incorrect. Utilisez le geste Rotor pour basculer entre les modes (« En-têtes », « Liens », « Boutons ») — chaque mode n'affichera que les éléments avec le trait correspondant.

Tests unitaires des traits sur iOS

Avant iOS 14, les tests unitaires n'avaient pas d'accès direct à accessibilityTraits. À partir d'iOS 14, la propriété est disponible : XCTAssertEqual(customButton.accessibilityTraits, .button). Utilisez cela dans les tests unitaires pour vérifier les contrôles personnalisés. Il est recommandé de tester chaque nouveau UIView personnalisé pour la correction du trait, en particulier après un refactoring ou un changement de classe parent.

Questions Fréquentes

Combien de traits peut-on attribuer à un élément ?

Jusqu'à 3-4 traits par élément. Un nombre plus élevé rend l'annonce VoiceOver redondante. Utilisez des combinaisons : Button + Selected, Header + StaticText.

Quel est le trait par défaut de UIButton ?

UIAccessibilityTraitButton. iOS le définit automatiquement pour toutes les instances de UIButton. Si vous héritez de UIView et simulez un bouton, le trait doit être défini manuellement.

Existe-t-il un trait « Adjustable » et à quoi sert-il ?

Oui, UIAccessibilityTraitAdjustable — pour les éléments avec des valeurs ajustables (curseurs, sélecteurs, compteurs). VoiceOver permet de balayer vers le haut/bas pour modifier la valeur et lire l'état actuel.

Comment vérifier les traits dans SwiftUI ?

Utilisez le modificateur .accessibilityAddTraits() : Text(« Titre »).font(.title).accessibilityAddTraits(.isHeader). La méthode fonctionne sur iOS 14+.

Que se passe-t-il si je ne définis pas de trait pour un contrôle personnalisé ?

VoiceOver attribuera le trait None. L'élément n'aura pas de rôle — le lecteur d'écran lira uniquement le Label sans indiquer le type. L'utilisateur ne saura pas si un geste d'activation est disponible.

Résumé

  • Accessibility Trait — un masque de bits UIAccessibilityTraits qui définit le rôle d'un élément iOS pour VoiceOver (Button, Header, Link, StaticText et autres)
  • Les traits sont combinés à l'aide du OU binaire ([] dans Swift), pas plus de 3-4 par élément
  • Les UIView personnalisés doivent recevoir un trait explicite — par défaut, il peut s'agir de None ou Image
  • Sur Android, le rôle est défini via className dans AccessibilityNodeInfo, sur Flutter — via semanticsRole
  • Un trait incorrect (StaticText pour un bouton) brise le scénario VoiceOver : aucun geste d'activation
  • Vérifiez les traits via Accessibility Inspector dans Xcode et le rotor VoiceOver
  • Dans SwiftUI, utilisez .accessibilityAddTraits() pour configurer les traits de manière déclarative

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi