Skip to content

@starting-style and Discrete Transitions

When to Use

To animate elements transitioning from display: none to visible — previously impossible in CSS alone. Also enables transitions on <dialog> and [popover] elements entering and exiting the page.

Decision

If you need... Use... Why
Animate a dialog or drawer opening @starting-style + transition-behavior: allow-discrete Browser reads start values from @starting-style
display: nonedisplay: block with transition Both allow-discrete AND @starting-style Two parts required — the discrete display change needs allow-discrete, the start values need @starting-style
Animate a popover appearing Same pattern as dialog Popovers use top-layer entry same as <dialog>
Complex orchestrated multi-step animation JS animation library CSS discrete transitions are linear; choreography needs JS

Pattern

Animating a <dialog> open and close:

dialog {
  opacity: 1;
  translate: 0 0;
  transition:
    opacity 0.3s ease,
    translate 0.3s ease,
    display 0.3s allow-discrete,  /* required for display: none transition */
    overlay 0.3s allow-discrete;  /* required to hold top-layer during exit */

  @starting-style {
    /* Values the browser reads BEFORE the element becomes visible */
    opacity: 0;
    translate: 0 -1rem;
  }
}

/* Exit — when dialog is not [open], animate toward these values */
dialog:not([open]) {
  opacity: 0;
  translate: 0 -1rem;
}

Three required pieces for enter/exit animation: 1. @starting-style block — start values for the enter transition 2. transition-behavior: allow-discrete on display — allows display to be part of transition 3. transition-behavior: allow-discrete on overlay — keeps top-layer elements visible during exit transition

Browser support: Chrome 117, Firefox 129, Safari 17.5. Baseline August 2024. Safe to use.

Common Mistakes

  • Omitting the overlay transition — the dialog disappears abruptly during exit because it leaves the top layer before the transition completes
  • Forgetting @starting-style — without it, the browser has no starting values and the enter transition does not play
  • Putting animation logic in @starting-style instead of transition@starting-style defines start state only; transitions are still declared on the element normally
  • Using animation instead of transition@starting-style only works with CSS transitions, not @keyframes animations

See Also