Contexte
À lire
- Prenez 5mn pour mieux comprendre la question de l’accessibilité numérique si ce n’est pas encore fait (site Bakhtech section Hello’ Accessibilité)
- Prenez 5mn pour naviguer comme un aveugle avec le lecteur d’écran intégré aux appareils sous iOS/iPad OS VoiceOver
- Ces 2 premiers points sont essentiels pour comprendre l’accessibilité numérique et constatés par soi même les impacts sur un utilisateur en situation de handicap. La prise en main de Voice Over vous sera aussi utile pour tester et valider vos corrections.
Recommandations
- Les images porteuses d’information doivent avoir une alternative textuelle pertinente (en utilisant accessibilityLabel)
- Les images décoratives doivent être ignorées par voice over. (Ce qui est le cas par défaut, il n y a donc rien à faire)
Objets et propriétés concernés
- Objets :
UIImageView
- Propriétés :
accessibilityLabel Ouvre un nouvel onglet
Code
//Donner une alternative textuelle à une image
imageView.accessibilityLabel = "Un texte alternatif pertinent"
- Ne jamais donner une information qu’avec la couleur
- Utiliser des contrastes de couleurs qui respectent les seuils exigés
Classes et propriétés concernés
- Classes :
UIView
- Propriétés :
color, background-color, tintColor
Cas particuliers – Notes techniques – Exceptions à la règle :
- Non concerné par les critères de contraste de couleur : Logo, dénomination commerciale
- Pour corriger les contrastes de couleur une alternative serait d’ajouter un bouton permettant d’inverser les couleurs ou de renforcer les contrastes sur l’ensemble de l’application en un “clic”.
Au delà des normes :
- Outils pour vérifier les contrastes de couleur : Contrast checker, plugin Sketch, plugin Figma
- Les médias doivent avoir :
- Une transcription textuelle adjacente ou accessible via un lien ou bouton adjacent ou des sous-titres synchronisés pour être accessibles aux personnes ayant un handicap auditif (si nécessaire)
- Une transcription textuelle ou une audiodescription adjacente accessible via un lien ou bouton adjacent pour être accessibles aux personnes ayant un handicap visuel (si nécessaire)
- Chaque son de plus de 3 secondes déclenché automatiquement doit être contrôlable par l’utilisateur (bouton stop, mute ou volume spécifique)
- Les boutons de controles des medias doivent être compatible avec les technologies d’assistances
Classes et Propriétés concernés
- Classes :
AVPlayer, AVPlayerViewController, WKWebView
Cas particuliers – Notes techniques – Exceptions à la règle :
- Le média est utilisé comme CAPTCHA ou test
- Le média est décoratif (dans ce cas, vérifier qu’il soit bien ignoré par Voice Over)
- Chaque bouton doit être explicite de par son intitulé ou en combinant celui ci avec son contexte
- Les boutons doivent avoir une zone cliquable de hauteur et largeur minimale de 44pt
Classes et propriétés concernés
- Classes :
UIButton
(ainsi que les composants ayant le même role qu’un bouton au toucher) - Propriétés :
setTitle, accessibilityLabel (Ouvre un nouvel onglet), accessibilityHint (Ouvre un nouvel onglet)
Code
//bouton texte
button.setTitle("Intitulé pertinent", for: .normal)
//bouton image
button.accessibilityLabel = "Un intitulé pertinant"
//Donner plus d'informations sur l'action du bouton
button.accessibilityHint = "Cliquez pour envoyer le formulaire de contact"
Au delà des normes :
- Il est également possible d’utiliser accessibilityHint pour compléter l’intitulé en donnant plus d’indications sur l’action du bouton (Voir exemple de code ci dessus)
- Les composants customs doivent être totalement contrôlables (utilisables) par les technologies d’assistances. Les informations suivantes en particulier : nom, role, valeur, paramétrage et changements d’état du composant doivent être restitués au lecteur d’écran. À défaut une alternative pertinente et fonctionnelle avec ces outils doit être proposée.
- Les messages de statut doivent être correctement restitués à Voice Over
Classes et propriétés concernés
- Classes :
UIView
- Propriétés :
accessibilityLabel Ouvre un nouvel onglet, accessibilityHint Ouvre un nouvel onglet, accessibilityTraits (Ouvre un nouvel onglet), accessibilityValue (Ouvre un nouvel onglet), accessibilityIncrement() (Ouvre un nouvel onglet) , accessibilityDecrement() (Ouvre un nouvel onglet),
Code
//Nom du composant (exemple avec un onglet custom)
tabView.accesibilityLabel = "Onglet 1 sur 2"
//Role et état du composant
tabView.accessibilityTraits = [.button,.selected]
//Valeur de l'élément (exemple : slider)
sliderView.accessibilityValue = "80%"
//Donner plus d'infos sur l'utilisation/actions du composant
sliderView.accessibilityHint
//Déclencher une vocalisation en cas de changement de contenu (permet également de mettre le focus voice over sur l'élément en question)
UIAccessibility.post(notification: .layoutChanged, argument: tabPanelLabel)
//Faire lire un texte par Voice Over
let message = NSAttributedString(
string: "Texte à vocaliser.",
attributes: [.accessibilitySpeechQueueAnnouncement: true]) /*indique à VoiceOver d'attendre la fin des annonces en court d'abord*/
UIAccessibility.post(notification: .announcement,
argument: message)
//Exemple : rendre un slider custom accessible à VoiceOver
class VolumeSlider : UIView {
var value = "50%"
override func layoutSubviews() {
super.layoutSubviews()
...
accessibilityLabel = "Volume"
accessibilityHint = "Ajuste la valeur du volume"
accessibilityTraits = .adjustable //Indique à voice over que c'est un élément dont la valeur est ajustable par l'utilisateur. Avec voice over actif, l'utilisateur peut alors glisser le doigt vers le haut pour incrémenter le slider ou vers le bas pour le décrémenter.
accessibilityValue = value
}
override func accessibilityIncrement() {
//fonction appelée lorsque l'on incrémente le slider via VoiceOver (en glissant le doigt vers le haut). Il faut executer ici executer la même action que pour une incrémentation normale puis mettre à jour la valeur annoncé par voice over
...
accessibilityValue = value
}
override func accessibilityDecrement() {
//Idem mais pour la décrémentation
...
accessibilityValue = value
}
}
//Utiliser les actions personnalisés pour effectuer des actions demandant des gestes complexes de manière simples avec VoiceOver (par exemple un glisser pour archiver un mail)
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
...
let archive = UIAccessibilityCustomAction(
name: "Archiver le mail",
target: self,
selector: #selector(archiveAction))
accessibilityCustomActions = [archive]
}
@objc func archiveMail() -> Bool {
//effectuer l'action puis retourner true ou alors retourner false si l'action n'est pas effectuable (Par exemple dans le cas d'un bouton page suivante, si on est déjà sur la dernière page)
}
}
Cas particuliers – Notes techniques – Exceptions à la règle :
- Il existe une gestion de cas particulier lorsque la fonctionnalité dépend de l’utilisation d’un gestionnaire d’événement sans équivalent universel ; par exemple, une application de dessin à main levée ne pourra pas être rendue contrôlable via les technologies d’assistances. Dans ces situations, le critère est non applicable.
Au delà des normes :
- Il est également possible d’utiliser les actions personnalisées pour tout simplement créer un raccourci. Par exemple, si on a un bouton en bas à droite de l’écran, on peut créer une action personnalisée ayant la même action que ce bouton pour éviter que l’utilisateur ait à parcourir toute la page afin de l’atteindre
- S’il n y a aucun correspondant au composant custom (par exemple pour les checkbox qui n’existent pas nativement sur iOS), indiquer le role du composant dans le accessibilityLabel
- Chaque écran doit avoir un titre qui lui est propre ou qui permet de se repérer dans la navigation
- Indiquer au lecteur d’écran les changements de langue dans une vue
Html, CSS et JS concernés
- Classes :
UILabel, UITextView
- Propriétés :
accessibilityLanguage Ouvre un nouvel onglet
Code
//Indiquer qu'un label contient du texte en anglais
label.accessibilityLanguage = "en"
- Utiliser accessibilityTraits pour indiquer qu’un texte est un titre
- Indiquer la présence de citation
- Classes :
UILabel, UITextView
- Propriétés :
accessibilityLabel Ouvre un nouvel onglet, accessibilityTraits Ouvre un nouvel onglet
Code
//Indiquer qu'un texte est un titre
titleLabel.accessibilityTraits = .header
//Indiquer qu'un texte est une citation
label.accessibilityLabel = "Citation : " + label.text
- Utiliser le type dynamique pour les textes afin que l’utilisateur puisse ajuster leur taille via les paramètres d’accessibilité
- Le contenu visible doit le rester quelque soit la taille de texte choisi par l’utilisateur
- La taille des glyphes apportant une information doivent également s’adapter à la taille de texte choisi
- Chaque lien dont la nature n’est pas évidente doit être visible par rapport à son environnement
- Les contenus cachés doivent aussi être ignorés par les technologies d’assistance
- Ne donner aucune information uniquement avec la forme, la taille ou la position
- Le contenu doit être présenté sans avoir besoin d’un scrolling vertical si le sens de lecture est horizontal d’un scrolling horizontal si le sens de lecture est vertical
Classes et propriétés concernés
- Classes :
UILabel, UITextView, UIFont, UIFontMetrics ,UIView, adjustsImageSizeForAccessibilityContentSizeCategory
- Propriétés :
adjustsFontForContentSizeCategory (Ouvre un nouvel onglet), isAccessibilityElement (Ouvre un nouvel onglet)
Code
//Masquer un élément à voice over
view.isAccessibilityElement = false
//Utiliser une police dynamique pour du texte (ici le corps du texte)
label.font = UIFont.preferredFont(forTextStyle: .body)
//Gérer le changement de taille de texte en temps réel (Au lieu de devoir rédémarrer l'appli pour voir les changements)
label.adjustsFontForContentSizeCategory = true
//Faire d'une police normale une police dynamique (Par exemple si la taille ou la police par défaut ne nous convient pas)
let labelFont = UIFont.boldSystemFont(ofSize: 30.0)
label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: labelFont)
label.adjustsFontForContentSizeCategory = true
//Adapter la taille d'une image de manière automatique
imageView.adjustsImageSizeForAccessibilityContentSizeCategory = true
//Adapter la taille d'un élément graphique manuellement
func adjustSize(){
let adjustedHeight = UIFontMetrics(forTextStyle: .body).scaledValue(for: 50.0)
buttonHeight.constant = adjustedHeight
...
}
override func viewDidLoad() { //au lancement
...
adjustSize();
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
//lorsque l'utilisateur change la taille du texte dans les paramètres
adjustSize();
}
Cas particuliers – Notes techniques – Exceptions à la règle :
- Dans le cas des textes en image et des sous-titres de vidéo le critère sur la lisibilité du contenu après zoom du texte n’est pas applicable
- Le critère sur l’absence scrolling n’est pas applicables sur les images, graphiques, vidéos, jeux, présentations, tableaux de données, interface où il est nécessaire d’avoir un ascenseur horizontal lors de la manipulation de l’interface et navigateurs mobiles
Au delà des normes :
- Liste des styles de textes dynamiques (Ouvre un nouvel onglet)
- Bien utiliser le style approprié au texte (Par exemple, ne pas utiliser un style largeTitle pour le corps du texte juste pour avoir une taille de texte plus grande. A la place, utiliser UIFontMetrics)
- Chaque champ du formulaire doit être associé à une étiquette pertinente, les 2 doivent être accolés (étiquette au dessus ou à gauche du champ)
- Si le champ est répété sur une page ou dans un ensemble de pages, cela doit être fait de manière cohérente
- Indiquer la présence de champ obligatoire ainsi que le type de données attendu si nécéssaire
- Utiliser le type de clavier correspondant au type de données à entrer pour faciliter la saisie
- Dans les cas suivants proposer à l’utilisateur de confirmer son action : modification ou suppression de données, réponse à un test ou à un examen, validation aux conséquences financières ou juridiques
Classes et Propriétés concernés
- Classes:
UITextField
- Propriétés :
accessibilityLabel (Ouvre un nouvel onglet), accessibilityHint (Ouvre un nouvel onglet), keyboardType, textContentType
Code
//Donner une étiquette accessible à un champ (En plus de l'étiquette texte accolée)
textField.accessibilityLabel = "Nom du champ"
//Donner plus d'informations sur un champ
textField.accessibilityHint = "Champ Obligatoire. Nombre entre 1 et 100"
//Changer le type de clavier pour un champ (ici clavier numérique)
textField.keyboardType = .numberPad
//Faciliter le remplissage automatique
textField.textContentType = .emailAddress
Au delà des normes :
- L’utilisateur doit avoir le contrôle de chaque limite de temps qui modifie le contenu
- L’ouverture d’une nouvelle fenêtre ne doit pas être déclenché sans action de l’utilisateur
- Les documents bureautiques en téléchargement doivent aussi être accessibles tout en apportant la même information
- Prévoir une alternative pertinente pour les contenus cryptiques (art ASCII, émoticon, syntaxe cryptique)
- Utiliser correctement les changements brusques de luminosité ou les effets flash
- Chaque contenu en mouvement ou clignotant doit être contrôlable par l’utilisateur
- Le contenu doit être consultable quelque soit l’orientation de l’écran
- Les fonctionnalités utilisables ou disponibles au moyen d’un geste complexe doivent aussi être disponibles à l’aide d’un geste simple
- les actions déclenchées au moyen d’un dispositif de pointage sur un point unique de l’écran peuvent-elles faire l’objet d’une annulation
- les fonctionnalités qui impliquent un mouvement de l’appareil ou vers l’appareil doivent pouvoir être satisfaites de manière alternative
Cas particuliers – Notes techniques – Exceptions à la règle :
- Le critère sur la limite de temps n’est pas applicable lorsque celle ci est essentielle, notamment lorsqu’elle ne pourrait pas être supprimée sans changer fondamentalement le contenu ou les fonctionnalités liées au contenu
- Le critère sur l’orientation de l’écran n’est pas applicable si celle ci est essentielle à l’utilisation de l’interface. (ex : jeu)
- Idem pour le critère sur les mouvements de l’appareil. (ex : podomètre)
- Le critère sur les gestes complexes ne s’appliquent pas aux gestes requis par l’agent utilisateur ou le système d’exploitation
- Idem pour le critère sur les actions déclenchées au moyen d’un dispositif de pointage. De plus les fonctionnalités qui imitent un clavier ne sont pas concernés