Passer au contenu

DDEHTML

Rethinking the Interactive Web

Ce document est un brouillon et ne constitue en aucun cas une spécification définitive.

Documentation de l'extension DARIA : Declarative Accessible Rich Internet Applications

Cette documentation présente la spécification initiale du langage DARIA, un langage de feuille de comportement conçu pour séparer l'interactivité de base du Web du JavaScript, rendant ainsi les documents plus robustes et accessibles par défaut.


Principes Fondamentaux de DARIA

  • Déclaratif : Le comportement est défini par des règles et des sélecteurs, similaire à CSS, décrivant la manière dont les éléments doivent interagir.
  • Accessibilité par Défaut : L'objectif est de résoudre de manière native les patterns ARIA Authoring Practices Guide sans recourir à du JavaScript.
  • Séparation des Responsabilités : DARIA est strictement limité à la manipulation du DOM (Attributs, Classes, ARIA). Il ne gère pas le style (domaine de CSS) ni la logique applicative complexe (domaine de JavaScript).

Structure d'une Feuille de Comportement DARIA

Une feuille de comportement est composée de règles. Chaque règle commence par un sélecteur (identique aux sélecteurs CSS) définissant les éléments ciblés, suivi d'un bloc de déclarations entre accolades.

Il y a principalement deux types de règles : les relations, préfixées par rel- et les événements, préfixés par on- ou par kb- dans le cas de la définition des interactions claviers.

Le nommage des relations peut être arbitraire. On recommandera de choisir un nom clair (exemple : rel-controlled ou rel-group).

sélecteur {
    rel-my-relationX: "mon-selecteur"; /* Définition des relations */
    rel-my-relationY: "mon-autre-selecteur";
    on-eventName: micro-action1(my-relationX, param) micro-action2(my-relationY, param); /* Définition des comportements */
    kb-key1-key2: micro-action(my-relationY); /* Interactions claviers */
    /* ... */
}

Certaines propriétés spéciales sont à l'étude. Par exemple la propriété order admettant un nombre entier en paramètre. Contrairement à son homologue CSS, il s'agira de déplacer réellement les éléments du DOM en fonction du contexte d'affichage (media queries, breakpoints)


Relations Déclaratives

Les relations sont la clé de DARIA, elles permettent de lier l'élément sélectionné à d'autres éléments cibles pour appliquer des actions. Elles sont définies par le préfixe rel-, suivi d'un nom choisi par l'intégrateur (ex: rel-controlled, rel-button).

Syntaxe des Relations

La valeur d'une relation doit être une chaîne de caractère décrivant un sélecteur, potentiellement préfixé d'un point de vue initial entre parenthèses.

Par défaut la point de vue initial est l'élément attrapé par le sélecteur. Cependant on souhaitera parfois établir une relation à partir de l'un de ses ancêtres, ou de son ancêtre directe.

rel-nom: "sélecteur-ou-fonction";
Ou :
rel-nom: "(initial-pov) sélecteur-ou-fonction";

Points de Vue Initiaux Prédéfinis (POV)

Ces mots-clés définissent l'élément à partir duquel le sélecteur de la relation sera appliqué.

POVDescription
rootRacine du document (<html>).
selfL'élément sélectionné par la règle DARIA.
parentL'élément parent direct.
nextLe prochain frère.
prevLe frère précédent.
branchTous les enfants de l'élément parent.
firstLe premier enfant de l'élément parent.
lastLe dernier enfant de l'élément parent.
siblingsTous les frères de l'élément sélectionné (sans l'élément lui-même).
siblings: sélecteurLes frères correspondant au sélecteur spécifié (sans l'élément lui-même).
closest: sélecteurLe plus proche ancêtre (ou l'élément lui-même) correspondant au sélecteur.

Enfin, la chaîne de caractère de la relation peut être calculée à partir d'un ou plusieurs de ses attributs de la même façon qu'avec CSS, grâce à la fonction attr().

Exemples de Relation :

#parent {
	rel-relation: "#selector";
}

Cette relation est très simple. Attention : son point de vue est (par défaut) l'élément "#parent". Cela signifie que #selector est supposé être un descendant de #parent.

rel-controlled: "#" attr(aria-controls);

Cette relation est arbitrairement nommée "controlled". Sa valeur n'est pas immédiatement une chaine de caractère (présence de la fonction attr()) et doit donc être calculée. Elle sera définie par le contenu de l'attribut aria-controls préfixé par "#".

rel-button: "(closest: #navigation) button[aria-controls=menu-principal]";

Cette dernière relation est un peu plus complexe que les deux autres. En effet, elle ne part pas directement de l'élément attrapé par le sélecteur, car elle est préfixée un point de vue initial entre parenthèses qui annonce le premier ancêtre correspondant à "#navigation" comme étant le point de départ de la selection. Enfin, le ou les descendants de "#navigation" qui satisfont "button[aria-controls=menu-principal]" seront le ou les éléments finalement ciblés par la relation nommée "button".

Une fois les relations définies, nous allons pouvoir appliquer des comportements aux éléments ciblés par ces relations. C'est le rôle des évènements et de leurs micro-actions.


Micro-Actions et Événements

Le comportement des éléments est définie via des propriétés d'événement (ex: on-click) qui contiennent une séquence de micro-actions exécutées de manière synchrone.

Ciblage des Micro-Actions

La cible d'une micro-action est le nom d'une relation ou self, suivi du préfixe @ pour un attribut ou d'un point . pour une classe.

CiblageDescriptionExemple
relation@attributCible un attribut sur les éléments liés par la relation.set(controlled@hidden)
relation.classeCible une classe sur les éléments liés par la relation.rm(controlled.mobile)
self@attributCible un attribut sur l'élément sélectionné.toggle(self@aria-expanded)

Événements

ÉvénementDescription
initExécuté une seule fois lors de l'initialisation du DOM par le navigateur, où lors de l'insertion de l'élément (satisfaisant le sélecteur) dans le DOM.
on-eventDésigne tout événement utilisateur (clic, survol, etc.), sauf les pressions clavier.
on-click-outÉvénement synthétique émis lors d'un clic en dehors de l'élément sélectionné et de tous les éléments liés par des relations.
kb-touche(s)Désigne la pression d'une touche ou d'une combinaison de touches (ex: kb-escape, kb-shift-tab).

Liste des Micro-Actions

Ces micro-actions constituent le vocabulaire de base de DARIA.

Elles sont la frontière délicate entre un langage déclaratif et un langage de programmation. Leur évolution devra être strictement encadrée par une spécification claire :

Elles seront toujours limitées à un nombres d'actions rudimentaires sur le DOM simples, dont l'implémentation hors Javascript permettra une execution optimal et sécurisée. Elles ne devront jamais permettre d'exécuter des opérations complexes (boucles, gros calculs, ou envoie de données vers l'extérieur).

Micro-ActionSyntaxeDescription
setset(cible@boolean-attr)

set(cible@attr, "valeur")

set(cible.classe)
Définit la valeur d'un attribut ou ajoute une classe.
rmrm(cible@attr)

rm(cible.classe)
Supprime un attribut ou une classe.
toggletoggle(cible@attr)

toggle(cible@attr, "v1", "v2", "v3")

toggle(cible.classe)
Inverse l'état d'un attribut/classe ou cycle à travers une liste de valeurs pour un attribut.
waitwait(ms)Met en pause l'exécution des micro-actions suivantes pour un nombre de millisecondes.
cancelcancel()Prévient le comportement par défaut de l'événement (équivalent de event.preventDefault()).
triggertrigger(cible, "nom-event")Émet un événement DOM personnalisé (qui peut être écouté par du JavaScript).
openopen(cible)Ouvre un élément (par exemple, pour <dialog>, équivalent JS : show()).
open-modalopen-modal(cible)Ouvre un élément en mode modal (par exemple, pour <dialog>, équivalent JS : showModal()).
closeclose(cible)Ferme un élément (par exemple, pour <dialog>, équivalent JS : close()).
start-loopstart-loop(cible, "nom")Démarre une boucle définie par l'intégrateur (utilisé pour les carrousels, etc.).
stop-loopstop-loop(cible, "nom")Arrête une boucle en cours.
prependprepend(cible-parent, cible-enfant)Insère un élément comme premier enfant.
appendappend(cible-parent, cible-enfant)Insère un élément comme dernier enfant.
scroll-toscroll-to(viewport, cible)Fait défiler un élément (viewport) jusqu'à ce que la cible soit visible.

Requêtes Média et Supports

Les règles DARIA peuvent être conditionnées par des requêtes médias ou la prise en charge native de certaines fonctionnalités.

Requêtes Média Standard

Les requêtes médias standard (telles que @media (max-width: 1200px) ou @media (prefers-reduced-motion: reduce)) sont entièrement prises en charge, permettant d'adapter le comportement déclaratif aux conditions de l'utilisateur ou de l'appareil.

Règles @supports

La règle @supports permet de définir un comportement de polyfill déclaratif si une fonctionnalité HTML native est absente.

Cette fonctionnalité permettra au navigateur de bénéficier de polyfills pour d'éventuels éléments HTML récents (ex : les invokers) y compris si javascript est désactivé.

@supports not (details) {
    /* Règles DARIA à appliquer si la balise <details> n'est pas prise en charge */
}
@supports not (button[commandfor]) {
    /* Règles DARIA à appliquer si l'attribut <commandfor> n'est pas prise en charge sur les boutons */
}

Exemple : Menu de Navigation Responsive

Voici l'exemple d'une implémentation d'un menu de navigation (avec bouton pour mobile) qui utilise l'attribut ARIA aria-expanded pour indiquer son état.

Comportement par Défaut (Ouverture)

button[aria-expanded][aria-controls] {
    rel-controlled: "#" attr(aria-controls); /* Lie le bouton au menu contrôlé */
    init: set(self@hidden) rm(controlled@hidden) rm(controlled.mobile); /* Masque le bouton par défaut si le menu est visible (état desktop) */
}

Comportement Mobile (Écran Réduit)

@media (max-width: 1200px) {

    button[aria-expanded][aria-controls] {
        /* Initialisation en mode mobile: le menu est masqué et le bouton affiché */
        init: set(controlled@hidden) set(controlled.mobile) set(self@aria-expanded, "false") rm(self@hidden);
        
        /* Clic sur le bouton : bascule l'état ARIA et l'attribut hidden du menu */
        on-click: toggle(self@aria-expanded, "true", "false") toggle(controlled@hidden);
        
        /* Clic en dehors du bouton/menu : ferme le menu */
        on-click-out: set(self@aria-expanded, "false") set(controlled@hidden);
        
        /* Touche Échapper (focus sur le bouton) : ferme le menu */
        kb-escape: set(self@aria-expanded, "false") set(controlled@hidden); 
    }

    #menu-principal a {
        rel-controlled: "(closest: #menu-principal)"; /* L'ancre contrôle son menu parent */
        rel-button: "(closest: #navigation) button[aria-controls=menu-principal]"; /* L'ancre a une relation vers le bouton du menu */
        
        /* Touche Échapper (focus sur une ancre du menu) : ferme le menu */
        kb-escape: set(button@aria-expanded, "false") set(controlled@hidden);
    }
}

Feuille de route

  1. Proposer un brouillon de spécification comme point de départ et objet de discussion (Rédaction en cours de ce document)
  2. Developper un polyfill JS de cette spécification permettant de faire exister ce langage indépendemment de son adoption. Cette implémentation servira de base expérimentale. Elle est en cours de développement.
    Elle se présentera sous une double forme :
    • Un polyfill JS pour embarquer le support de DARIA dans les pages HTML.
    • Une WebExtension permettant à l'utilisateur de désactiver l'execution de Javascript à partir des pages visitées ("Secured mode") tout en conservant l'expérience offerte par cette implémentation
    Bien que cette première implémentation soit en JS, gardons bien à l'esprit que son objectif est d'établir et d'offrir un langage dont l'objectif est d'être totallement indépendant de Javascript.
  3. Au cours du développement du langage DARIA, de nouvelle balises HTML fondées sur les ARIA APG seront sans doutes proposées. De plus, ce langage servira aussi à l'élaboration (hors javascript) de polyfills pour des éléments HTML modernes (ex : les invokers). C'est un argument en faveur d'une navigation sécurisée et du principe de progressive enhancement.
  4. Après de nombreuses discussions ainsi qu'une couverture suffisante des patterns ARIA Authoring Practices Guide, il sera temps d'encourager les developpeurs de sites web ainsi que les implémenteurs des navigateurs populaire d'adopter DARIA

Conclusion

Actuellement, le language DARIA est à un stade expérimental.

Son élaboration définitive et sa standardisation devra reposer sur une l'approbation d'une communauté ouverte : le groupe de travail DDEHTML du W3C.

Son adoption dépendra de sa popularité parmi les developpeurs, et du bon vouloir des implémenteurs de chaques navigateur.

Cependant, une implémentation JS en cours de développement par défaut permetra de faire exister cette initiative indépendament de son adoption.

Si vous souhaitez soutenir cette initiative, ou si vous souhaitez simplement recevoir des information sur l'évolution de ce projet, vous pouvez rejoindre cette communauté.

Une mailing liste sera bientôt créée, écrivez-nous pour vous inscrire.