Start · Sprachen · JavaScript · Referenz · SpeechSynthesisUtterance: boundary

SpeechSynthesisUtterance: boundary

Ereignis

Wird ausgelöst, wenn die Sprachsynthese beim Vorlesen einer <code>SpeechSynthesisUtterance</code> eine Wort- oder Satzgrenze erreicht.

seit JavaScript Web Speech API – Chrome 33+, Edge 14+, Safari 7+, Kategorie: webapi

Signatur

utterance.addEventListener("boundary", handler)

Beschreibung

Das Ereignis boundary gehört zu SpeechSynthesisUtterance und wird während der Sprachausgabe jedes Mal ausgelöst, wenn die Synthese-Engine eine Wortgrenze (name === "word") oder eine Satzgrenze (name === "sentence") erreicht. Der Handler bekommt ein SpeechSynthesisEvent übergeben.

Typisch ist der Einsatz zum Mitlesen, also zum Hervorheben des gerade gesprochenen Wortes (Karaoke-Effekt), für Fortschrittsanzeigen, zur Synchronisation mit Animationen oder für Hilfen zur Barrierefreiheit. Über event.charIndex und event.charLength findet man die passende Stelle im Text utterance.text.

Den Listener registriert man entweder mit utterance.addEventListener("boundary", handler) oder über die Eigenschaft utterance.onboundary = handler. Er muss gesetzt sein, bevor speechSynthesis.speak(utterance) aufgerufen wird. Sonst können frühe Ereignisse verloren gehen.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Ereignisname "boundary".
$handler Pflicht (event: SpeechSynthesisEvent) => void Callback mit einem SpeechSynthesisEvent. Wichtige Eigenschaften: name ("word" oder "sentence"), charIndex (Startposition im Text), charLength (Länge des Wortes, kann 0 oder undefiniert sein), elapsedTime (Sekunden seit Sprechbeginn) und utterance.
$options boolean | AddEventListenerOptions false Optionale Listener-Optionen wie once oder signal.

Rückgabewert

Typ
void
Beschreibung
addEventListener gibt nichts zurück. Der Handler erhält ein SpeechSynthesisEvent.

Beispiele

Wortgrenzen mit addEventListener protokollieren

const utterance = new SpeechSynthesisUtterance('Hallo Welt. Wie geht es dir?');
utterance.lang = 'de-DE';

utterance.addEventListener('boundary', (event) => {
  const word = utterance.text.slice(event.charIndex).match(/^\S+/)?.[0] ?? '';
  console.log(`${event.name} bei Index ${event.charIndex} (${event.elapsedTime.toFixed(2)} s): ${word}`);
});

speechSynthesis.speak(utterance);
word bei Index 0 (0.00 s): Hallo word bei Index 6 (0.41 s): Welt. sentence bei Index 12 (0.80 s): Wie ...

Gesprochenes Wort im Text hervorheben (onboundary)

// HTML: <p id="text"></p> <button id="play">Vorlesen</button>
const textEl = document.querySelector('#text');
const text = 'Die Web Speech API liest diesen Satz Wort für Wort vor.';
textEl.textContent = text;

const escapeHtml = (s) => s.replace(/[&<>"]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c]));

document.querySelector('#play').addEventListener('click', () => {
  const utterance = new SpeechSynthesisUtterance(text);
  utterance.lang = 'de-DE';

  utterance.onboundary = (event) => {
    if (event.name !== 'word') return;
    const start = event.charIndex;
    // charLength fehlt in manchen Browsern – Fallback per Regex
    const length = event.charLength || (text.slice(start).match(/^\S+/)?.[0].length ?? 0);
    textEl.innerHTML =
      escapeHtml(text.slice(0, start)) +
      '<mark>' + escapeHtml(text.slice(start, start + length)) + '</mark>' +
      escapeHtml(text.slice(start + length));
  };

  utterance.onend = () => { textEl.textContent = text; };

  speechSynthesis.cancel();
  speechSynthesis.speak(utterance);
});

Fortschritt anzeigen und Listener per AbortController entfernen

const text = 'Erster Satz. Zweiter Satz. Dritter Satz.';
const utterance = new SpeechSynthesisUtterance(text);
const controller = new AbortController();

const onBoundary = (event) => {
  const percent = Math.round((event.charIndex / text.length) * 100);
  console.log(`Fortschritt: ${percent} %`);
  if (percent >= 50) {
    // Nach der Hälfte keine Updates mehr
    utterance.removeEventListener('boundary', onBoundary);
  }
};

utterance.addEventListener('boundary', onBoundary, { signal: controller.signal });
utterance.addEventListener('end', () => controller.abort(), { once: true });

speechSynthesis.speak(utterance);
Fortschritt: 0 % Fortschritt: 15 % Fortschritt: 33 % Fortschritt: 50 %

// Wichtig · Fallstricke

  • Von der Stimme abhängig: Ob boundary überhaupt ausgelöst wird, hängt von der Synthese-Engine ab. Viele Online- bzw. Netzwerkstimmen in Chrome (z. B. „Google Deutsch“) senden keine boundary-Ereignisse. Lokale Systemstimmen tun das meistens. Das Hervorheben sollte daher nur eine optionale Verbesserung sein.
  • name kann abweichen: Manche Browser liefern nur "word" und nie "sentence". Firefox und Safari verhalten sich hier unterschiedlich.
  • charLength ist erst neuer spezifiziert und in älteren Browsern undefined oder 0. Die Wortlänge lässt sich dann ab charIndex per Regex bestimmen.
  • SSML/Satzzeichen: charIndex bezieht sich auf utterance.text. Bei Abkürzungen, Zahlen oder Emojis stimmen die Grenzen nicht immer mit der erwarteten Wortzerlegung überein.
  • Sicherheit: Wer beim Hervorheben mit innerHTML arbeitet, muss den Text escapen, sonst droht XSS bei Nutzereingaben. Alternativ baut man DOM-Knoten auf oder nutzt die CSS Custom Highlight API.
  • Den Listener immer vor speechSynthesis.speak() registrieren. Nach speechSynthesis.cancel() kommen keine weiteren Ereignisse.