Signatur
Beschreibung
Das Ereignis transitioncancel gehört zu einer Gruppe von Ereignissen, mit denen du den Ablauf einer CSS-Transition verfolgen kannst: transitionrun (Transition erstellt), transitionstart (nach Ablauf von transition-delay gestartet), transitionend (erfolgreich beendet) und transitioncancel (abgebrochen). Nach einem Abbruch wird kein transitionend mehr ausgelöst. Deshalb solltest du transitioncancel immer dann mit abfragen, wenn deine Logik (Aufräumen, Zustand zurücksetzen, Promise auflösen) sonst nicht ausgeführt würde.
Ein Abbruch passiert u. a., wenn während der Transition der Wert von transition-property so geändert wird, dass die laufende Eigenschaft nicht mehr enthalten ist, wenn das Element display: none bekommt oder aus dem DOM entfernt wird, oder wenn die Transition durch eine neue Transition derselben Eigenschaft ersetzt wird.
Du registrierst den Handler per addEventListener("transitioncancel", handler) oder über die Eigenschaft ontransitioncancel. Der Handler bekommt ein TransitionEvent mit den Eigenschaften propertyName (die betroffene CSS-Eigenschaft), elapsedTime (bis zum Abbruch vergangene Laufzeit in Sekunden, ohne Verzögerung) und pseudoElement (z. B. "::before" oder leerer String). Das Ereignis steigt auf (bubbles) und ist nicht abbrechbar.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignisname "transitioncancel". |
|
| $handler Pflicht | (event: TransitionEvent) => void | Callback, der ein TransitionEvent mit propertyName, elapsedTime und pseudoElement erhält. |
|
| $options | boolean | AddEventListenerOptions | false | Optionen wie once, capture, passive oder signal (zum Entfernen per AbortController). |
Rückgabewert
addEventListener gibt nichts zurück. Dem Handler wird ein TransitionEvent übergeben.Beispiele
Abbruch einer Transition erkennen
// CSS: .box { transition: transform 1s; } .box.moved { transform: translateX(200px); }
const box = document.querySelector('.box');
box.addEventListener('transitioncancel', (event) => {
console.log(`Abgebrochen: ${event.propertyName} nach ${event.elapsedTime.toFixed(2)} s`);
});
box.classList.add('moved');
// Nach 300 ms die Transition entfernen -> Abbruch
setTimeout(() => {
box.style.transition = 'none';
}, 300);
Promise, das bei Ende ODER Abbruch aufgelöst wird
const waitForTransition = (el, property) =>
new Promise((resolve) => {
const controller = new AbortController();
const done = (event) => {
if (event.target !== el || event.propertyName !== property) return;
controller.abort(); // beide Listener entfernen
resolve(event.type === 'transitionend' ? 'beendet' : 'abgebrochen');
};
el.addEventListener('transitionend', done, { signal: controller.signal });
el.addEventListener('transitioncancel', done, { signal: controller.signal });
});
const panel = document.querySelector('.panel');
panel.classList.add('open');
const result = await waitForTransition(panel, 'opacity');
console.log(`Transition ${result}`);
ontransitioncancel-Eigenschaft und Entfernen des Listeners
const menu = document.querySelector('#menu');
const onCancel = (event) => {
menu.classList.remove('is-animating');
console.log('Animation abgebrochen, Zustand zurückgesetzt');
};
// Variante 1: on-Property (nur ein Handler möglich)
menu.ontransitioncancel = onCancel;
// Variante 2: addEventListener / removeEventListener
menu.ontransitioncancel = null;
menu.addEventListener('transitioncancel', onCancel);
// Später wieder entfernen
menu.removeEventListener('transitioncancel', onCancel);
// Wichtig · Fallstricke
- Kein
transitionendnach Abbruch: Wer nur auftransitionendhört, bleibt bei abgebrochenen Transitions in einem Zwischenzustand hängen (z. B. Klasseis-animatingwird nie entfernt). Behandle darum immer beide Ereignisse. - Bubbling: Das Ereignis steigt auf. Transitions von Kindelementen lösen den Handler am Elternelement ebenfalls aus – prüfe
event.targetundevent.propertyName. - Kurzschreibweisen: Bei
transition: alloder Kurzschreibweisen wiepaddinggibt es ein Ereignis pro einzelner Eigenschaft (z. B.padding-left). - Entfernen aus dem DOM: Wird das Element entfernt, erreicht das Ereignis unter Umständen keine Listener mehr an Vorfahren, weil das Element nicht mehr im Baum hängt. Browser verhalten sich hier nicht ganz einheitlich.
- Kompatibilität: Firefox unterstützt das Ereignis schon lange; Chrome/Edge erst ab Version 87, Safari ab 13.1. Für ältere Browser brauchst du einen Fallback per Timeout. Für CSS-Animationen (
@keyframes) ist stattdessenanimationcancelzuständig.