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.

Open
Open and close both. In Chrome each one fades and rises in, then fades out before it is removed, and the dialog's backdrop fades with it. With Reduce Motion on they still fade, and do not move.
Code CSS · 42 lines
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 3 reasons · 5 rules · support · credits

Why it works

  1. @starting-style gives the browser a "before open" state to transition from when the element leaves display: none. That is the entry.
  2. allow-discrete on display delays the switch to display: none until the other transitions finish. That is the exit. overlay keeps the element in the top layer meanwhile.
  3. The fade is not motion, so it runs for everyone. Only the slide sits inside the reduced-motion query.

Rules

  1. Put @starting-style after the open-state rule. It has no extra weight in the cascade.
  2. Never start from scale(0). If the element scales in, start at scale(0.95) with opacity: 0.
  3. The dialog's ::backdrop needs the same three states and its own transition, as in the block. Without them it snaps while the dialog fades.
  4. Write no fallback. Where the exit is not supported the element closes at once.
  5. Keep [popover]:popover-open out 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 at opacity: 0. Inside @starting-style the 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