Signatur
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
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);
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) => ({ '&': '&', '<': '<', '>': '>', '"': '"' }[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);
// 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. namekann abweichen: Manche Browser liefern nur"word"und nie"sentence". Firefox und Safari verhalten sich hier unterschiedlich.charLengthist erst neuer spezifiziert und in älteren Browsernundefinedoder0. Die Wortlänge lässt sich dann abcharIndexper Regex bestimmen.- SSML/Satzzeichen:
charIndexbezieht sich aufutterance.text. Bei Abkürzungen, Zahlen oder Emojis stimmen die Grenzen nicht immer mit der erwarteten Wortzerlegung überein. - Sicherheit: Wer beim Hervorheben mit
innerHTMLarbeitet, 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. NachspeechSynthesis.cancel()kommen keine weiteren Ereignisse.