Billets publiés en novembre 2009 ↓

ARIA et validation : comment faire ?

Stéphane Deschamps me pique la plume. Le sujet se prête mieux au format de ce blog qu’au sien.

Un peu d’histoire

L’idée d’ARIA c’est de permettre de décrire des rôles et des états, pour améliorer l’accessibilité des clients riches. Ainsi on peut légalement avec ARIA faire une case à cocher en image, pourvu qu’on la décrive comme une case à cocher (role="checkbox") et qu’on indique son état, cochée (aria-checked). C’est pratique pour faire des graphismes modernes, tout en permettant de ne pas sacrifier l’accessibilité au seul profit de ceux qui ont des yeux et une souris, pour résumer.

Quand ARIA a été introduit, on ne parlait pas encore de HTML 5 au W3C : c’est XHTML qui prévalait. Or en XHTML une notion fondamentale est celle des espaces de nommage, permettant de rattacher au document courant (dont l’espace de nommage HTML est implicite) des extensions. ARIA bénéficiait donc d’une déclaration dans le document pour permettre à chacun de ses attributs d’être déclaré avec le préfixe aria:. Par exemple le rôle d’un élément s’écrivait aria:checkbox. Facile.

Avec l’avènement de HTML 5 et ses choix différents en termes de formalisme, qui privilégient l’écriture de code avec la syntaxe HTML, ARIA a dû faire machine arrière : tout a été renommé sans espace de nommage. Les deux points des propriétés spécifiques à ARIA ont été remplacés par des tirets : aria:checked devient aria-checked. Certains attributs quant à eux, qui ont du sens même hors du contexte d’ARIA, n’ont carrément pas de préfixe. C’est le cas de role, qui était prévu dans la spécification XHTML 2.

Pour l’accessibilité dans le monde réel, c’est presque une bonne chose : à ce jour, la revue d’écran la plus utilisée (Jaws) ne reconnaît pas les attributs préfixés. J’en ai fait la douloureuse expérience lorsque mon site est passé en XHTML : Jaws ne comprenait pas les attributs xml:lang et les ignorait purement et simplement ! (Il a fallu doubler tous ces attributs avec l’attribut HTML classique lang).

Oui mais voilà : et la validation dans tout ça ?

À ce jour, le validateur du W3C s’appuie sur le DOCTYPE que vous déclarez dans votre code pour vérifier que vous respectez bien sa grammaire. Or dans une spécification ancienne (XHTML 1.1 date de 2001), il n’était évidemment pas prévu d’intégrer des attributs dont on ignorait qu’ils existeraient un jour ! Sans compter que la logique même d’extensibilité du XHTML venait de l’idée qu’on intégrerait tout ça avec des espaces de nommage, donc l’extension était prévue, mais avec un formalisme que le brouillon courant de HTML 5 remet en cause. Bref, nous voilà au pied du mur : faut-il faire du code invalide, ou respecter maniaquement la spécification et trouver des contournements « légaux » ?

Une solution : opter pour du code invalide

La solution simple serait d’opter pour du code invalide. Eric Meyer considère qu’on peut prôner les standards en étant fidèle à l’esprit mais pas toujours à la lettre : c’est ce qu’il appelle standards-oriented.

En l’occurrence, imaginons que j’aie écrit une page conforme et que j’y rajoute des attributs ARIA. Elle devient non-valide, mais j’ignore les erreurs en connaissance de cause parce que je suis un développeur Web avisé, et que je sais que ça ne posera pas de souci aux navigateurs tout en améliorant l’accessibilité pour tous.

Utiliser un attribut HTML existant et manipuler ses valeurs avec JavaScript

La deuxième solution est plus sportive : je crée du code valide, et je profite de JavaScript pour ajouter les attributs qui me manquent.

Cas classique : je repère l’élément via son id (identifiant unique dans la page), et j’ajoute le ou les attributs dont j’ai besoin pour faire de l’ARIA.

Oui mais : tous mes éléments ne sont pas forcément nommés, pourtant je risque d’avoir besoin de nombreux endroits auxquels me raccrocher pour ajouter des propriétés ARIA.

Le plus simple sera alors d’utiliser un attribut HTML, d’en extraire le contenu et de générer les attribut ARIA à partir de là.

Quel attribut choisir ?

J’ai déjà vu des gens utiliser l’attribut rel des liens, par exemple pour faire des popins (rel="popin,450,300" indique qu’à ce lien sera ajouté un comportement JavaScript d’affichage de la popin, et les dimensions de ladite popin). Pour ma part j’en suis très gêné, il me semble qu’il s’agit là d’un détournement assez osé de l’attribut. Par ailleurs, ça ne fonctionne que sur des liens ; il faut donc trouver un attribut plus générique.

En revanche, la bonne idée depuis plusieurs années, c’est tout de même qu’on tente de ne pas mettre de comportement dans le code. On s’appuie sur le DOM pour inventorier les éléments auxquels affecter tel ou tel comportement, souvent en passant par l’attribut class. Pour revenir à notre exemple de popins, il y a quelques années on aurait fait la même chose en popup, en s’appuyant sur la classe : class="popup".

Essayons donc de nous appuyer sur la classe : il nous semble moins nocif d’utiliser cet attribut plutôt qu’un autre.

Quelle méthode ?

Maintenant que nous avons choisi la classe, quelle convention d’écriture adopter pour tous ces attributs ?

Première proposition, utiliser une notation héritée de JSON : class="{role:contentinfo;}". Son intérêt c’est qu’elle est facile à interpréter, et qu’elle sera extensible si nous devons ajouter plusieurs attributs : class="{role:checkbox;aria-checked:true;}". Son gros défaut c’est qu’elle a l’apparence d’une verrue dans le code, sans compter que cette notation ressemble suffisamment à la notation classique des paires propriété / valeur de CSS pour au mieux prêter à confusion chez le développeur moins au fait que vous, au pire faire tousser un navigateur dont le parseur de code y reconnaîtrait de la CSS (scénario catastrophe, me direz-vous ; oui mais on a déjà vu pire dans certains navigateurs).

Deuxième proposition : utiliser une notation à base de tirets, class="role-contentinfo", et manipuler la chaîne en l’explosant pour générer l’attribut et sa valeur.

Deux situations à différencier

Attention cependant, ARIA propose une approche deux-en-un :

  1. description d’éléments de structure de la page à travers le rôle (les landmarks) ;

  2. description d’éléments interactifs (typiquement les éléments de formulaire).

Selon moi ces deux cas peuvent impliquer une approche différente : le premier cas doit tant qu’à faire fonctionner même sans JavaScript, le deuxième n’a souvent de sens que si JavaScript fonctionne (puisque le changement dynamique d’état ne peut se faire qu’avec JavaScript).

Conclusion

Je serais enclin à faire du code invalide, en particulier dans le cas des landmarks, mais plus partagé sur les propriétés dynamiques (rôles et états des éléments interactifs).

À votre avis ? Faut-il du code invalide, et si oui, quelle méthode choisiriez-vous ?