Le Focus Order est la séquence dans laquelle les éléments de l'interface reçoivent le focus lors de la navigation avec un clavier, Switch Control, VoiceOver ou TalkBack. Dans les applications mobiles, l'ordre de focus détermine comment l'utilisateur se déplace entre les contrôles via des gestes ou des boutons. Selon W3C WCAG 2.2, Success Criterion 2.4.3, 2023, le focus doit suivre un ordre logique qui préserve le sens du contenu. La violation de ce principe est l'une des causes fréquentes d'échec d'un audit d'accessibilité.
Points clés
Focus Order est la séquence dans laquelle l'utilisateur se déplace entre les éléments interactifs avec des méthodes de saisie alternatives : clavier (Tab), Switch Control (pas à pas), VoiceOver (glisser droite/gauche) ou TalkBack. Contrairement à une souris ou un écran tactile, où l'utilisateur sélectionne un élément directement, la navigation par focus est linéaire — chaque étape déplace le focus vers l'élément suivant.
Selon Apple HIG, 2024, VoiceOver utilise l'ordre des éléments dans l'arbre d'accessibilité, qui est construit en fonction de l'emplacement visuel : coin supérieur gauche → coin inférieur droit. Si l'écran a une disposition complexe (colonnes, Grid, ZStack), l'arbre peut ne pas correspondre à l'ordre visuel.
Principe WCAG 2.4.3 : «Si une page web peut être naviguée séquentiellement à travers des sections et que l'ordre de focus affecte le sens, alors le focus doit suivre un ordre qui préserve le sens et l'opérabilité». Exception : contenu dynamique où le focus peut sauter pour attirer l'attention (alertes, fenêtres modales).
Un utilisateur de Switch Control (personnes avec des troubles moteurs) se déplace automatiquement entre les éléments — cycle après cycle. Si l'ordre est brisé, l'utilisateur met 3 fois plus de temps à remplir le formulaire. Selon Deque University, 2024, un Focus Order correct réduit le temps de remplissage du formulaire de 60% pour les utilisateurs de technologies d'assistance.
Une attention particulière — les fenêtres modales. Après l'ouverture d'une modale, le focus doit immédiatement se déplacer vers le premier élément interactif à l'intérieur de la modale (généralement un bouton «Fermer» ou «Confirmer»). Après la fermeture — revenir à l'élément qui a déclenché la modale. C'est une exigence de WCAG 2.4.3 et aussi une erreur courante.
Dans iOS, VoiceOver construit automatiquement l'ordre basé sur la géométrie : les éléments sont triés par Y, puis par X. Pour les écrans avec une structure complexe, cet ordre peut être incorrect — le développeur doit intervenir.
Outils principaux :
Exemple de définition d'ordre personnalisé pour une carte produit :
class ProductCardView: UIView {
let titleLabel = UILabel()
let priceLabel = UILabel()
let buyButton = UIButton()
override var accessibilityElements: [Any]? {
get {
return [titleLabel!, priceLabel!, buyButton!]
}
set {}
}
}
Pour un déplacement programmatique du focus après une action :
UIAccessibility.post(
notification: .layoutChanged,
argument: newlyAddedItem
)
La propriété shouldGroupAccessibilityElement est utile pour les cartes dans les collections. Si définie sur true sur la carte parent, VoiceOver perçoit la carte entière comme un seul élément. L'utilisateur peut double-cliquer pour activer la carte entière, ou configurer le rotor pour la navigation interne. Recommandé pour UICollectionViewCell et UITableViewCell.
Dans Android, TalkBack utilise également l'ordre géométrique, mais la priorité est donnée aux attributs explicites nextFocus*. Ces attributs sont définis en XML ou programmatiquement :
| Attribut | Objectif | Exemple |
|---|---|---|
| nextFocusDown | Élément lors de la navigation vers le bas | @+id/field_email |
| nextFocusUp | Élément lors de la navigation vers le haut | @+id/field_name |
| nextFocusLeft | Élément à gauche | @+id/btn_back |
| nextFocusRight | Élément à droite | @+id/btn_next |
Exemple pour un formulaire d'inscription :
<EditText
android:id="@+id/field_email"
android:nextFocusDown="@+id/field_password" />
<EditText
android:id="@+id/field_password"
android:nextFocusDown="@+id/btn_submit" />
Pour RecyclerView, l'ordre de focus est dynamique — déterminé par l'adaptateur. Si les cellules ont une structure complexe, définissez descendantFocusability = «beforeDescendants» et définissez l'ordre dans le nœud de l'élément de liste. Pour Jetpack Compose, l'ordre de focus est défini via Modifier.focusOrder() et FocusOrder. Priorité : previous (enfant), next (suivant), clé personnalisée.
Si un élément est trop petit pour le focus (moins de 44pt), augmentez la zone de contact via TouchDelegate dans iOS ou minWidth/minHeight dans Android. Selon Google Material Design, 2024, la zone tactile minimale est de 48×48dp. VoiceOver et TalkBack se concentrent sur la boîte englobante de l'élément. Les éléments de moins de 30pt peuvent être inaccessibles au focus gestuel — l'utilisateur ne peut physiquement pas les toucher.
Focus sauteur — quand après une action (par exemple, supprimer un élément) le focus se déplace au début de la liste ou vers le bouton système «Retour». L'utilisateur VoiceOver perd le contexte. Solution : déplacer programmatiquement le focus vers l'élément le plus proche de celui supprimé.
Focus invisible — un élément reçoit le focus mais il n'y a pas d'indicateur visuel (les utilisateurs de clavier ne voient pas où ils sont). Dans iOS, vérifiez UIAccessibility.isVoiceOverRunning pour les indicateurs personnalisés. Selon Deque University, 2024, le focus invisible est la deuxième cause la plus fréquente d'échec d'un audit d'accessibilité.
Modales — le focus reste sur le contenu d'arrière-plan après l'ouverture d'une modale. Dans iOS, la vue modale capture automatiquement le focus si modalPresentationStyle = .pageSheet est défini. Dans Android, utilisez setFocusable(true) sur le conteneur de la boîte de dialogue.
Le problème inverse : le focus reste coincé à l'intérieur d'une modale et ne peut pas en sortir (sauf en la fermant). C'est acceptable uniquement pour les fenêtres modales — l'utilisateur doit fermer la fenêtre intentionnellement. Pour les écrans normaux, le piège de focus est une erreur critique. Solution : assurez-vous que le dernier élément de la modale (le bouton «Fermer») rend le focus.
Pour les écrans personnalisés (cartes, canevas, jeux), l'ordre géométrique automatique n'est pas applicable. Le développeur doit construire l'arbre d'accessibilité manuellement. Dans iOS, la méthode UIAccessibilityContainer est surchargée à cet effet.
Exemple pour un canevas personnalisé :
class CanvasView: UIView {
var shapes: [ShapeView] = []
override var accessibilityElements: [Any]? {
get {
// Trier les formes par Z-index, pas par géométrie
return shapes.sorted { $0.zIndex < $1.zIndex }
}
set {}
}
}
Dans Android, pour une vue personnalisée, surchargez onInitializeAccessibilityNodeInfo :
override fun onInitializeAccessibilityNodeInfo(
info: AccessibilityNodeInfo
) {
super.onInitializeAccessibilityNodeInfo(info)
info.addChild(firstElement)
info.addChild(secondElement)
info.isFocusable = true
}
Pour les listes dynamiques (chat, fil d'actualités), après avoir ajouté un élément, déplacez le focus vers le premier nouvel élément. Dans iOS : UIAccessibility.post(notification: .layoutChanged, argument: newMessage). Dans Android : sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED).
iOS détermine automatiquement la zone de focus en fonction du cadre de l'élément. Si un élément a une transformation (transform, rotation), VoiceOver peut se concentrer sur la mauvaise zone. Définissez explicitement accessibilityFrame en coordonnées d'écran : element.accessibilityFrame = UIAccessibility.convertToScreenCoordinates(element.bounds, in: element). Cela garantit que VoiceOver met en évidence la bonne zone.
Pour les écrans animés (UIKit Dynamics, Lottie, SpriteKit), le focus programmatique est particulièrement important. VoiceOver ne peut pas construire un arbre d'accessibilité pour les éléments en mouvement dynamique. Définissez isAccessibilityElement = false sur les conteneurs d'animation et true uniquement sur les éléments interactifs à l'intérieur.
Test manuel : activez VoiceOver (iOS) ou TalkBack (Android), balayez vers la droite sur toute la séquence. Le focus doit suivre l'ordre visuel — de gauche à droite, de haut en bas. Chaque élément interactif doit recevoir le focus exactement une fois.
Tests automatisés sont difficiles mais possibles :
func testKeyboardFocusOrder() {
let app = XCUIApplication()
app.launch()
app.textFields["Email"].tap()
// Tab — clavier matériel uniquement
}
Pour Android, utilisez le Accessibility Testing Framework :
@Test
fun testFocusOrder() {
onView(withId(R.id.fieldEmail))
.check(matches(isFocusable()))
onView(withId(R.id.fieldEmail))
.perform(focus())
onView(withId(R.id.fieldPassword))
.check(matches(isFocused()))
}
La méthode la plus fiable est un test de scénario d'interface : remplissez le formulaire étape par étape (Email → Mot de passe → Envoyer), en vérifiant que chaque étape se termine avec succès. Si l'ordre de focus est brisé, le scénario échouera en tentant d'interagir avec un élément hors focus.
L'outil Accessibility Inspector dans Xcode affiche l'arbre d'accessibilité complet. Vous pouvez parcourir les éléments dans l'ordre de VoiceOver et voir le chemin de focus exact. Utilisez l'onglet «Audit» pour la détection automatique des violations de Focus Order.
Questions fréquentes
WCAG 2.4.3 (Focus Order) est un critère de succès de niveau A. Il exige que l'ordre de focus préserve le sens du contenu lors de la navigation séquentielle. La violation est considérée comme critique et bloque la certification.
Les éléments cachés doivent avoir isAccessibilityElement = false dans iOS ou visibility = gone/invisible dans Android. Lorsqu'ils apparaissent, déplacez programmatiquement le focus via UIAccessibility.post(notification: .layoutChanged).
iOS gère via accessibilityElements et shouldGroupAccessibilityElement, Android via les attributs nextFocus* et AccessibilityNodeInfo. Le principe est le même : ordre géométrique par défaut avec possibilité de substitution.
Définissez descendantFocusability = «beforeDescendants» sur l'élément racine et configurez l'ordre dans l'adaptateur via onInitializeAccessibilityNodeInfo pour chaque cellule.
Connectez un clavier physique via Bluetooth ou USB. Sur iOS, appuyez sur Tab pour déplacer le focus. Sur Android, activez TalkBack et utilisez la touche Tab et les flèches.
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