From c42be31aab159e4c91d7d04a6373607b99c1b82c Mon Sep 17 00:00:00 2001 From: Christopher Abate Date: Mon, 3 Nov 2025 11:01:07 +0100 Subject: [PATCH 1/3] Update index.njk --- .../faire-parler-le-lecteur-d-ecran/index.njk | 81 ++++++++++--------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/src/fr/articles/faire-parler-le-lecteur-d-ecran/index.njk b/src/fr/articles/faire-parler-le-lecteur-d-ecran/index.njk index 1c4e0b4e34..af7aecd3d3 100644 --- a/src/fr/articles/faire-parler-le-lecteur-d-ecran/index.njk +++ b/src/fr/articles/faire-parler-le-lecteur-d-ecran/index.njk @@ -1,6 +1,6 @@ --- title: "Faire parler le lecteur d'écran à l'aide de JavaScript et ARIA" -abstract: "Exemple de code permettant de faire parler la synthèse vocale." +abstract: "Exemple de code permettant de faire parler la synthèse vocale grâce aux régions dynamiques ARIA." titleBeforeTag: true date: "2018-01-04" tags: @@ -9,56 +9,65 @@ js: - script.js --- +

Article mis à jour le ...

+

Préambule

-

Dans certains cas, il peut être intéressant de vouloir faire parler le lecteur d'écran, pour confirmer une action utilisateur par exemple. Dans cet exemple, nous allons voir comment ceci peut être réalisé simplement à l'aide de l'attribut aria-live.

+

Dans certaines interfaces, il peut être utile de faire annoncer automatiquement une information par un lecteur d'écran, par exemple pour confirmer une action ou signaler un changement dynamique. Cette fonctionnalité repose sur l'utilisation des régions dynamiques ARIA (aria-live) combinées à JavaScript.

Principe de fonctionnement

-

L'attribut aria-live positionné sur un élément permet d'indiquer au lecteur d'écran que cet élément doit être vocalisé automatiquement lorsque son contenu est modifié.

-

Les valeurs possibles sont :

- - - -

Et en Javascript ?

-

Cette première solution permet dans bien des cas de rendre son application accessible. Il existe tout de même quelques cas où il serait pratique de pouvoir faire parler le lecteur d'écran directement à l'aide d'une fonction Javascript (exemple : speak('Article supprimé du panier')). Malheureusement ceci n'est pas disponible nativement.

-

Heureusement, on peut rapidement réaliser une petite fonction Javascript qui utilisera un élément aria-live sous le capot pour réaliser cette fonctionnalité.

+

L'attribut aria-live appliqué à un élément indique au lecteur d'écran que les modifications de contenu doivent être annoncées automatiquement. Les valeurs principales sont :

+ +

Pour compléter le comportement, il est possible d'utiliser :

+ -

À l'appel de la fonction speak, on ajoute une div à la fin de la page. On lui affecte un attribut aria-live et on insère le message à vocaliser dans la div. Pour ne pas que ce message soit visible dans la page, on peut ajouter également une classe de masquage accessible sur cette div, ainsi celle-ci sera vocalisée mais ne sera pas visible à l'écran.

+

Faire parler le lecteur d'écran avec JavaScript

+

Il n'existe pas de fonction native pour faire parler directement le lecteur d'écran. Cependant, on peut créer une petite fonction JavaScript qui utilise une région dynamique ARIA sous le capot pour annoncer un message :

Détail du code


-  /* srSpeak(text, priority)
-    text : le message à vocaliser
-    priority (facultatif) : "polite" (par défaut) ou "assertive" */
+/* announceToScreenReader(message, priority)
+   message : le texte à vocaliser
+   priority : "polite" (par défaut) ou "assertive" */
 
-  function srSpeak(text, priority) {
-      var el = document.createElement("div");
-      var id = "speak-" + Date.now();
-      el.setAttribute("id", id);
-      el.setAttribute("aria-live", priority || "polite");
-      el.classList.add("visually-hidden");
-      document.body.appendChild(el);
+function announceToScreenReader(message, priority = "polite") {
+    const region = document.createElement("div");
+    const id = "sr-" + Date.now();
 
-      window.setTimeout(function () {
-        document.getElementById(id).innerHTML = text;
-      }, 100);
+    region.setAttribute("id", id);
+    region.setAttribute("aria-live", priority);
+    region.setAttribute("aria-atomic", "true");
+    region.classList.add("visually-hidden");
 
-      window.setTimeout(function () {
-          document.body.removeChild(document.getElementById(id));
-      }, 1000);
-  }
+    document.body.appendChild(region);
+
+    // Attendre un court délai pour que le lecteur d'écran détecte la région
+    setTimeout(() => {
+        region.textContent = message;
+    }, 50);
+
+    // Supprimer la région après annonce
+    setTimeout(() => {
+        document.body.removeChild(region);
+    }, 2000);
+}
 
-

Rappel : pour que les messages vocalisés ne soient pas visibles à l'écran vous devez avoir une classe de masquage accessible (visually-hidden) dans vos CSS.

-

Exemple

+

Rappel : pour que les messages soient vocalisés mais pas visibles, vous devez avoir une classe de masquage accessible (visually-hidden) dans vos CSS.

+ +

Exemple interactif

+

Vous pouvez tester cette fonction avec le formulaire ci-dessous (à tester avec un lecteur d'écran).

-

Vous pouvez tester cette fonction grâce au formulaire ci-dessous (à tester avec un lecteur d'écran, sinon on n’entend rien).

- + From d4bba9291653afb7f72d382db306655e4114e6b0 Mon Sep 17 00:00:00 2001 From: Christopher Abate Date: Mon, 3 Nov 2025 11:01:51 +0100 Subject: [PATCH 2/3] Update script.js --- .../faire-parler-le-lecteur-d-ecran/script.js | 50 +++++++++++-------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/src/fr/articles/faire-parler-le-lecteur-d-ecran/script.js b/src/fr/articles/faire-parler-le-lecteur-d-ecran/script.js index d4b0162fad..6a53c25b24 100644 --- a/src/fr/articles/faire-parler-le-lecteur-d-ecran/script.js +++ b/src/fr/articles/faire-parler-le-lecteur-d-ecran/script.js @@ -1,24 +1,32 @@ -document.addEventListener("DOMContentLoaded", function(event) { - document.getElementById('btnSpeak').addEventListener('click',function(){ - let message = document.getElementById('message'); - srSpeak(message.value); - message.value=""; - }) +document.addEventListener("DOMContentLoaded", () => { + const btn = document.getElementById('btnSpeak'); + const input = document.getElementById('message'); + + btn.addEventListener('click', () => { + if(input.value.trim() !== "") { + speak(input.value); + input.value = ""; + input.focus(); + } + }); }); -function srSpeak(text, priority) { - var el = document.createElement("div"); - var id = "faire-parler-le-lecteur-d-ecran-" + Date.now(); - el.setAttribute("id", id); - el.setAttribute("aria-live", priority || "polite"); - el.classList.add("visually-hidden"); - document.body.appendChild(el); - - window.setTimeout(function () { - document.getElementById(id).innerHTML = text; - }, 100); - - window.setTimeout(function () { - document.body.removeChild(document.getElementById(id)); - }, 1000); +function speak(message, priority = "polite") { + const region = document.createElement("div"); + const id = "sr-" + Date.now(); + + region.setAttribute("id", id); + region.setAttribute("aria-live", priority); + region.setAttribute("aria-atomic", "true"); + region.classList.add("visually-hidden"); + + document.body.appendChild(region); + + setTimeout(() => { + region.textContent = message; + }, 50); + + setTimeout(() => { + document.body.removeChild(region); + }, 2000); } From cfee856f1966900ac0415bb9ce9867d7a6b5a710 Mon Sep 17 00:00:00 2001 From: Christopher Abate Date: Mon, 3 Nov 2025 11:15:12 +0100 Subject: [PATCH 3/3] Update script.js --- src/fr/articles/faire-parler-le-lecteur-d-ecran/script.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/fr/articles/faire-parler-le-lecteur-d-ecran/script.js b/src/fr/articles/faire-parler-le-lecteur-d-ecran/script.js index 6a53c25b24..5f18ee3c4f 100644 --- a/src/fr/articles/faire-parler-le-lecteur-d-ecran/script.js +++ b/src/fr/articles/faire-parler-le-lecteur-d-ecran/script.js @@ -21,6 +21,12 @@ function speak(message, priority = "polite") { region.classList.add("visually-hidden"); document.body.appendChild(region); + + if (priority === "assertive") { + speechSynthesis.cancel(); + } + speechSynthesis.cancel(); + speechSynthesis.speak(new SpeechSynthesisUtterance(message)); setTimeout(() => { region.textContent = message;