# CSS Micro-interaction Recipes Modern CSS handles most UI motion with zero JavaScript, including enter/exit and `display` toggles. Baseline-available in current Chrome/Edge/Safari/Firefox (verify `@starting-style` and `allow-discrete` for your support floor; degrade to instant show/hide otherwise). ## Enter animation on first render: @starting-style `@starting-style` supplies the values an element transitions FROM the first time it renders (or becomes shown). Without it, there is no "previous" state to transition from, so newly-inserted elements snap in. ```css .menu { opacity: 1; transform: translateY(0); transition: opacity 0.2s ease, transform 0.2s ease; } @starting-style { .menu { opacity: 0; transform: translateY(-8px); } } ``` ## Animating to/from display:none: transition-behavior: allow-discrete `display` and `content-visibility` are discrete properties — normally they flip instantly, killing exit animations. `allow-discrete` lets them flip at the correct moment (kept visible during exit, swapped at the end). ```css .drawer { transition: transform 0.25s ease, opacity 0.25s ease, display 0.25s allow-discrete; /* keep displayed through the exit */ } .drawer[hidden] { /* closed state */ opacity: 0; transform: translateX(100%); display: none; } @starting-style { .drawer:not([hidden]) { opacity: 0; transform: translateX(100%); } } ``` Shorthand alternative: `transition-behavior: allow-discrete;` applies to all discrete properties in the `transition` list. ## Popover / dialog exit animation (top-layer) Native `popover` and `` live in the top layer via the `overlay` property, which is also discrete — animate it too: ```css [popover] { opacity: 0; transform: scale(0.95); transition: opacity 0.2s, transform 0.2s, overlay 0.2s allow-discrete, display 0.2s allow-discrete; } [popover]:popover-open { opacity: 1; transform: scale(1); } @starting-style { [popover]:popover-open { opacity: 0; transform: scale(0.95); } } ``` This gives a fully CSS-driven open AND close animation for `