Entry 01
Enter and exit transitions from display: none
Use it for dialogs, popovers and anything else toggled with display. It replaces a script that adds classes and waits for transitionend.
Code
dialog,
[popover] {
opacity: 0;
transition:
opacity 0.2s var(--ease-out, ease-out),
translate 0.2s var(--ease-out, ease-out),
display 0.2s allow-discrete,
overlay 0.2s allow-discrete;
}
dialog::backdrop {
opacity: 0;
transition:
opacity 0.2s var(--ease-out, ease-out),
display 0.2s allow-discrete,
overlay 0.2s allow-discrete;
}
dialog[open],
dialog[open]::backdrop { opacity: 1; }
[popover]:popover-open { opacity: 1; }
@starting-style {
dialog[open],
[popover]:popover-open,
dialog[open]::backdrop { opacity: 0; }
}
@media (prefers-reduced-motion: no-preference) {
dialog,
[popover] { translate: 0 0.5rem; }
dialog[open] { translate: 0 0; }
[popover]:popover-open { translate: 0 0; }
@starting-style {
dialog[open],
[popover]:popover-open { translate: 0 0.5rem; }
}
}Why it works, the rules and the credits
Why it works
@starting-stylegives the browser a "before open" state to transition from when the element leavesdisplay: none. That is the entry.allow-discreteondisplaydelays the switch todisplay: noneuntil the other transitions finish. That is the exit.overlaykeeps the element in the top layer meanwhile.- The fade is not motion, so it runs for everyone. Only the slide sits inside the reduced-motion query.
Rules
- Put
@starting-styleafter the open-state rule. It has no extra weight in the cascade. - Never start from
scale(0). If the element scales in, start atscale(0.95)withopacity: 0. - The dialog's
::backdropneeds the same three states and its own transition, as in the block. Without them it snaps while the dialog fades. - Write no fallback. Where the exit is not supported the element closes at once.
- Keep
[popover]:popover-openout of the selector list that opens the dialog. A browser that does not know one selector in a list drops the whole rule, and the dialog would open atopacity: 0. Inside@starting-stylethe shared list is safe, because every browser that reads the block knows the selector.
Support
Both directions in Chrome 117. In Safari 27 the entry animates and <dialog> and popovers close at once, tested in real Safari on 2026-10-01. An element toggled with a class animates both ways there. Firefox 129 animates the entry only.
Credits
Borrowed from: Una Kravets and Joey Arhar, Four new CSS features for smooth entry and exit animations · Kevin Powell, Transition to and from display: none, 2026-07-22 · Chris Coyier, In-N-Out Animations: Dialogs, 2026-06-01 · Adam Argyle, Steal this popover code, 2024-03-15 · Ahmad Shadeed, Grouping vendor selectors, Defensive CSS, for the split rules