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 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.
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.
iOS fournit plus de 15 constantes de traits. Examinons les principales utilisées dans 90% des scénarios :
| Trait | Constante | Comportement VoiceOver |
|---|---|---|
| Button | UIAccessibilityTraitButton | Activation par double tap |
| Header | UIAccessibilityTraitHeader | Navigation rapide par en-têtes |
| Link | UIAccessibilityTraitLink | Activation comme lien |
| StaticText | UIAccessibilityTraitStaticText | Lecture seule, sans activation |
| SearchField | UIAccessibilityTraitSearchField | Champ de recherche avec comportement spécial |
| Image | UIAccessibilityTraitImage | Image, sans geste d'activation |
| Selected | UIAccessibilityTraitSelected | État « sélectionné » |
| PlaysSound | UIAccessibilityTraitPlaysSound | Joue un son à l'activation |
| KeyboardKey | UIAccessibilityTraitKeyboardKey | Touche de clavier |
| TabBar | UIAccessibilityTraitTabBar | É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().
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.
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 :
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 :
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 ».
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.
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.
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. »
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.
Sur Android, il n'y a pas d'équivalent direct aux traits. Au lieu d'un masque de bits, on utilise :
Pour les Views personnalisés sur Android, vous devez redéfinir onInitializeAccessibilityNodeInfo :
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.
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.
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.
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 :
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.
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
Jusqu'à 3-4 traits par élément. Un nombre plus élevé rend l'annonce VoiceOver redondante. Utilisez des combinaisons : Button + Selected, Header + StaticText.
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.
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.
Utilisez le modificateur .accessibilityAddTraits() : Text(« Titre »).font(.title).accessibilityAddTraits(.isHeader). La méthode fonctionne sur iOS 14+.
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é
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.
Lisez aussi