@starting-style + transition-behavior: allow-discrete
Baseline 2024 (Chrome 117, Safari 17.5, Firefox 129).
Chrome 117
Edge 117
Safari 17.5
Firefox 129
Lets you transition from `display:none` and other discrete properties. `@starting-style` defines the "before first render" values so entry animations work; `allow-discrete` keeps the element displayed until the exit transition ends.
Saved. Click anywhere to dismiss.
CSS
.fx-014{
inset:auto 16px 16px auto;background:#111;color:#fff;padding:12px 16px;border:0;border-radius:10px;font-family:system-ui;
opacity:0;translate:0 16px;
transition:opacity .25s,translate .25s,display .25s allow-discrete,overlay .25s allow-discrete;
}
.fx-014:popover-open{opacity:1;translate:0 0}
@starting-style{.fx-014:popover-open{opacity:0;translate:0 16px}}
.fx-014 :is(a,button,input,select,textarea):focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
HTML
<button popovertarget="fx-014-toast">Show toast</button>
<div id="fx-014-toast" popover class="fx-014">Saved. Click anywhere to dismiss.</div>Fallback: Unsupported browsers show and hide instantly; the popover still works.
Source: developer.mozilla.org/en-US/docs/Web/CSS/@starting-style
Prompt
For enter/exit animations of elements that toggle `display`, do not use JS class timing. Set the visible state normally, put the initial hidden values in `@starting-style { .el:open {...} }` for the entry, and include `display .3s allow-discrete` (plus `overlay` for top-layer elements) in the transition list so the exit animation can play before the element disappears.