Wie man `display: none` ohne JavaScript-Hacks animiert
Animieren Sie display none mit CSS via allow-discrete und @starting-style sowie overlay für dialog und popover und Hinweise zur Browserunterstützung.
Um ein Element mit reinem CSS zu oder von display: none zu animieren, fügen Sie display zu Ihrer transition mit dem Schlüsselwort allow-discrete hinzu und definieren Sie den Einstiegszustand in einer @starting-style-Regel — kein JavaScript, kein setTimeout, kein transitionend-Listener. Zwei Features wurden entwickelt, um dies zu ermöglichen: transition-behavior: allow-discrete erlaubt diskreten Eigenschaften wie display die Teilnahme an einer Transition, und @starting-style gibt dem Browser einen „Vor-dem-Öffnen”-Zustand, von dem aus animiert werden kann. Dieser Leitfaden bietet Ihnen direkt verwendbare Ein- und Ausstiegs-Rezepte, den Dialog/Popover-Top-Layer-Fall mit seiner overlay-Besonderheit sowie eine ehrliche Einschätzung der aktuellen Browser-Unterstützung.
Wichtigste Erkenntnisse
- Animieren Sie
display, indem Sie es mitallow-discretein dietransition-Kurzschreibweise einbeziehen und den Einstiegszustand in einem@starting-style-Block definieren — kein JavaScript erforderlich. displayist eine diskrete Eigenschaft: Mitallow-discretesetzt der Browser sie beim Einblenden aufblockbei 0% und beim Ausblenden aufnonebei 100%, sodass der Inhalt während der gesamten Dauer sichtbar bleibt.- Wenn Sie die eigenständige Schreibweise
transition-behavior: allow-discreteverwenden, muss diese nach dertransition-Kurzschreibweise stehen, sonst ignoriert der Browser sie. - Verwenden Sie bei Dialogen und Popovers zusätzlich
overlay ... allow-discretein der Transition, behandeln Sie dies jedoch als Progressive Enhancement, daoverlaynoch kein Baseline-Feature ist. @starting-styleundallow-discretesind seit dem Release von Firefox 129 am 6. August 2024 als Baseline Newly Available eingestuft; ohne Unterstützung erscheint und verschwindet das Element einfach sofort.
Warum display: none bisher nicht animiert werden konnte
Eine CSS-Transition benötigt einen Stil vor der Änderung, von dem aus animiert werden kann. Ein Element mit display: none — oder eines, das gerade in den DOM eingefügt wurde — hat keinen gerenderten Vorzustand, weshalb der Browser historisch gesehen nichts interpolieren konnte und die Transition nie ausgelöst wurde. Aus diesem Grund griffen Entwickler auf setTimeout-Klassen-Toggling oder doppelte requestAnimationFrame-Reflow-Hacks zurück.
Der verbreitete Workaround — Ausblenden mit opacity: 0 bei gleichzeitigem Verbleib des Elements im DOM — ist kein vollwertiger Ersatz. opacity: 0 lässt das Element im Layout, in der Tab-Reihenfolge und im Accessibility-Tree, sodass Tastatur- und Screenreader-Nutzer weiterhin auf Inhalte stoßen können, die optisch verschwunden wirken. display: none entfernt es aus allen dreien. In der Praxis zeigen Session-Replays von halb migrierten Komponenten genau diese Fehlerklasse: Ein Nutzer, der per Tab oder Klick in einen Bereich gelangt, der geschlossen wirkt, aber nur ausgeblendet und nie aus dem Layout entfernt wurde. Die Animation von echtem display: none beseitigt dieses Problem.
Discover how at OpenReplay.com.
Die zwei CSS-Features, die das Problem lösen: allow-discrete und @starting-style
display ist eine diskrete Eigenschaft — sie kann nicht zwischen Werten interpolieren, sie ist ein Ein/Aus-Schalter. Diskret animierte Eigenschaften wechseln im Allgemeinen bei 50% der Animation zwischen zwei Werten; die Ausnahme bildet die Animation zu oder von display: none oder content-visibility: hidden, bei der der Browser zwischen den beiden Werten so wechselt, dass der animierte Inhalt während der gesamten Animationsdauer sichtbar bleibt. Die Richtung spielt dabei eine Rolle: Bei der Animation von display: none zu block wechselt der Wert bei 0% der Dauer auf block, sodass er durchgehend sichtbar ist; bei der Animation von block zu none wechselt er bei 100% der Dauer auf none, sodass er ebenfalls durchgehend sichtbar bleibt — was dafür sorgt, dass das Ausblenden in beide Richtungen tatsächlich sichtbar ist.
Sie aktivieren dies, indem Sie transition-behavior: allow-discrete für die display-Transition setzen, und definieren den Einstiegszustand mit @starting-style.
Das Ausstiegs-Rezept: Transition zu display: none
Um ein Element auszublenden und anschließend aus dem Layout zu entfernen, fügen Sie display mit allow-discrete in die transition ein und setzen den ausgeblendeten Zustand:
.panel {
opacity: 1;
transition: opacity 0.3s ease, display 0.3s allow-discrete;
}
.panel.is-hidden {
opacity: 0;
display: none;
}
Die Deckkraft animiert über 300ms auf 0; display verbleibt bis 100% auf seinem sichtbaren Wert und wechselt dann auf none. Vergessen Sie allow-discrete bei display, verschwindet das Element sofort — der häufigste Fehler bei dieser Technik.
Das Einstiegs-Rezept: Animation aus display: none
Für ein Element, das zunächst ausgeblendet ist, legen Sie die „Vor-dem-Öffnen”-Werte in einer @starting-style-Regel fest. Mit CSS-Nesting lebt das Ganze in einem einzigen Block:
.panel {
display: none;
opacity: 0;
transition: opacity 0.3s ease, display 0.3s allow-discrete;
}
.panel.is-open {
display: block;
opacity: 1;
@starting-style {
opacity: 0;
}
}
Die Reihenfolge ist entscheidend. @starting-style hat dieselbe Spezifität wie die Regel, auf die es abzielt, und muss daher nach der Deklaration des geöffneten Zustands stehen, um in der Kaskade zu gewinnen. Und es gibt eine einzeilige Falle: Wenn Sie transition-behavior: allow-discrete vor der transition-Kurzschreibweise angeben, ignoriert der Browser das transition-behavior. Als eigenständige Eigenschaft muss es zuletzt stehen:
.panel {
transition: opacity 0.3s, display 0.3s;
transition-behavior: allow-discrete; /* muss NACH der Kurzschreibweise stehen */
}
Für ältere Rendering-Engines deklariert das Cross-Browser-Muster von MDN transition zweimal — die erste Instanz ohne allow-discrete gewährleistet browserübergreifende Kompatibilität, sodass die anderen Eigenschaften auch in Browsern ohne Unterstützung für transition-behavior weiterhin animiert werden.
Dialoge und Popovers: Die overlay-Besonderheit
Top-Layer-Elemente — <dialog> und alles, das das popover-Attribut verwendet — sind der wichtigste Anwendungsfall, und sie haben eine zusätzliche Anforderung. Bei Dialogen und Popovers müssen Sie auch overlay ... allow-discrete in die Transition einbeziehen, da das Element sonst sofort aus dem Top-Layer fällt und die Ausstiegsanimation nie angezeigt wird:
dialog {
translate: 0 100vh;
transition:
translate 0.4s ease-out,
display 0.4s allow-discrete,
overlay 0.4s allow-discrete;
}
dialog[open] {
translate: 0 0;
@starting-style {
translate: 0 100vh;
}
}
Ersetzen Sie für ein Popover dialog[open] durch die Pseudoklasse :popover-open. Die overlay-Eigenschaft ist es, die das Entfernen aus dem Top-Layer verzögert: Sie stellt sicher, dass das Entfernen des Elements aus dem Top-Layer aufgeschoben wird, bis die Animation abgeschlossen ist; in komplexeren Fällen kann das Weglassen dazu führen, dass das Element zu früh aus dem Overlay entfernt wird, was die Animation unflüssig oder wirkungslos macht.
Ein wichtiger Vorbehalt, den andere oft übergehen: overlay ist kein Baseline-Feature. MDN kennzeichnet es als experimentell — dieses Feature ist nicht Baseline, da es in einigen der am häufigsten verwendeten Browser nicht funktioniert. Behandeln Sie es als Progressive Enhancement; wo es nicht unterstützt wird, öffnet und schließt sich der Dialog weiterhin, nur ohne den verzögerten Ausstieg.
Browser-Unterstützung und Graceful Degradation
@starting-style und transition-behavior: allow-discrete wurden beide mit Firefox 129, veröffentlicht am 6. August 2024, als Baseline Newly Available eingestuft. Die Animation von display selbst erfordert jedoch mehr als nur diese beiden Features. Es funktioniert in Chrome und Edge ab Version 117 sowie in Safari ab Version 18 — Safari 17.4 fügte transition-behavior hinzu und 17.5 @starting-style, aber die Transition von display mit diesen Features funktioniert erst ab Safari 18. Firefox 129+ unterstützt beide Features, animiert jedoch Stand Mitte 2026 die display-Eigenschaft noch immer nicht, sodass das Element in Firefox sofort ein- und ausblendet. display in @keyframes funktioniert seit Chrome 116.
| Feature | Status | Fallback |
|---|---|---|
transition-behavior: allow-discrete | Baseline (Aug. 2024) | Sofortiges Ein-/Ausblenden |
@starting-style | Baseline (Aug. 2024) | Keine Einstiegsanimation |
overlay | Nicht Baseline | Dialog öffnet/schließt sich weiterhin |
Dies ist reines Progressive Enhancement. Ohne diese Features erscheinen Elemente, die in den Top-Layer animiert werden oder von einem display: none-Stil ausgehen, einfach ohne Transition auf der Seite — so wie es heute der Fall ist. Kein Polyfill, kein JavaScript-Fallback. Grenzen Sie die Verbesserung mit Feature-Detection explizit ab, wenn Sie eine klare Trennlinie wünschen:
@supports (transition-behavior: allow-discrete) {
/* moderne Ein-/Ausstiegsanimationen */
}
Wann stattdessen View Transitions einsetzen
Verwenden Sie diese Transitions, wenn Sie die Sichtbarkeit eines bestehenden Elements umschalten. Greifen Sie stattdessen auf die View Transitions API zurück, wenn Sie DOM-Knoten hinzufügen oder entfernen. Same-Document View Transitions sind seit dem 14. Oktober 2025 als Baseline Newly Available eingestuft, nach dem Release von Firefox 144 am selben Tag — unterstützt in Chrome 111+, Edge 111+, Safari 18+ und Firefox 144+. Kapseln Sie die DOM-Mutation in document.startViewTransition() mit einem einfachen Fallback:
if (document.startViewTransition) {
document.startViewTransition(() => card.remove());
} else {
card.remove();
}
Das moderne Rezept löst die alte JavaScript-Choreografie ab: Fügen Sie display mit allow-discrete in Ihre transition ein, definieren Sie den Einstiegszustand in @starting-style, ergänzen Sie overlay für Top-Layer-Elemente, und lassen Sie nicht unterstützte Browser auf einen sofortigen Wechsel zurückfallen. Verabschieden Sie sich von setTimeout und setzen Sie auf CSS.
Häufig gestellte Fragen
Warum wird meine Ausstiegsanimation nicht ausgelöst, obwohl ich allow-discrete zur display-Transition hinzugefügt habe?
Die häufigste Ursache ist, dass die eigenständige Deklaration transition-behavior: allow-discrete vor der transition-Kurzschreibweise steht, weshalb der Browser sie stillschweigend ignoriert. Als separate Eigenschaft muss transition-behavior nach der transition-Kurzschreibweise stehen, da die Kurzschreibweise sie sonst zurücksetzt. Wenn Sie allow-discrete direkt in den transition-Wert einbetten, spielt die Reihenfolge innerhalb der Kurzschreibweise keine Rolle und diese Falle tritt nicht auf.
Benötige ich @starting-style noch, wenn ich ein Element nur zu display: none ausblenden möchte?
Nein. @starting-style ist nur für Einstiegsanimationen erforderlich, bei denen das Element von display: none ausgeht oder frisch in den DOM eingefügt wurde und einen Vor-dem-Öffnen-Zustand benötigt, von dem aus animiert werden kann. Ein reiner Ausstieg — die Animation eines bereits sichtbaren Elements zu display: none — erfordert lediglich, dass display mit allow-discrete in die transition einbezogen und der ausgeblendete Zustand gesetzt wird. Fügen Sie @starting-style nur dann hinzu, wenn Sie das Element auch beim Einblenden animieren möchten.
Was passiert in Browsern, die transition-behavior oder @starting-style nicht unterstützen?
Das Element erscheint und verschwindet einfach sofort, genau wie ohne jegliche Animation. Da es sich um Progressive Enhancement handelt, sind weder ein Polyfill noch ein JavaScript-Fallback erforderlich. Bei Dialogen und Popovers öffnen und schließen sich Elemente in Browsern ohne Unterstützung für die nicht-Baseline-Eigenschaft overlay weiterhin korrekt; der verzögerte Top-Layer-Ausstieg wird lediglich übersprungen. Sie können die Verbesserung explizit mit einer @supports (transition-behavior: allow-discrete)-Regel eingrenzen.
Wann sollte ich stattdessen die View Transitions API verwenden anstatt display: none zu animieren?
Verwenden Sie View Transitions, wenn Sie DOM-Knoten hinzufügen oder entfernen, und Display-Transitions, wenn Sie die Sichtbarkeit eines bereits im DOM vorhandenen Elements umschalten. Same-Document View Transitions wurden am 14. Oktober 2025 als Baseline Newly Available eingestuft und werden in Chrome 111+, Edge 111+, Safari 18+ und Firefox 144+ unterstützt. Kapseln Sie die DOM-Mutation in document.startViewTransition() mit einem einfachen Fallback für nicht unterstützte Engines.