Animate display: none in Pure CSS! Modern @starting-style & allow-discrete Explained
For over 10 years, transitioning elements from display: none was considered impossible in pure CSS without JavaScript reflow workarounds like requestAnimationFrame or void element.offsetWidth. Those days are officially over!
Modern CSS introduces two game-changing features (Baseline 2024 across Chrome, Safari, and Firefox):
@starting-style: Defines the before-change style snapshot at frame 0 when an element transitions fromdisplay: noneor mounts to the DOM.transition-behavior: allow-discrete: Delays flipping todisplay: noneuntil your exit transitions finish completely.
💡 The Mental Model: The Broadway Stage Analogy
To understand why this is necessary, think of a browser render engine like a Broadway theater:
- Without
@starting-style: Togglingdisplay: nonetodisplay: blockis like an actor suddenly teleporting from backstage straight into a 100% bright spotlight. The browser cannot interpolate between "does not exist in the render tree" and "fully visible", so it abruptly snaps. - With
@starting-style:@starting-styleplaces the actor on their backstage floor tape mark in the dark (opacity: 0,scale: 0.85) before the curtains open. Once the stage lights go up, they smoothly fade and scale into center stage. - With
allow-discrete: When closing,allow-discreteacts like a curtain timer. It lets the exit fade play out completely before turning off the lights and sending the element backstage.
🚀 3 Real-World Production Patterns
Pattern 1: Dropdown Menus & Modals (display: none → flex)
.modal {
display: flex;
opacity: 1;
transform: translateY(0);
transition: opacity 0.35s ease, transform 0.35s ease, display 0.35s allow-discrete;
/* Frame 0 snapshot when switching from display: none */
@starting-style {
opacity: 0;
transform: translateY(-12px);
}
}
.modal.is-closed {
display: none;
opacity: 0;
transform: translateY(-12px);
}
Pattern 2: Native HTML5 <dialog> and ::backdrop Transitions
You can animate the native <dialog> element and its top-layer ::backdrop with zero JavaScript wrapper elements:
dialog {
opacity: 1;
transform: scale(1);
transition: opacity 0.3s ease, transform 0.3s ease, overlay 0.3s allow-discrete, display 0.3s allow-discrete;
&::backdrop {
background-color: rgba(0, 0, 0, 0.65);
transition: background-color 0.3s ease, display 0.3s allow-discrete;
}
}
@starting-style {
dialog[open] {
opacity: 0;
transform: scale(0.92);
&::backdrop {
background-color: transparent;
}
}
}
Pattern 3: Dynamic DOM Elements & Toast Notifications
When appending elements dynamically with JavaScript (element.appendChild), modern CSS allows them to animate on first paint automatically:
.toast {
opacity: 1;
transform: translateX(0);
transition: opacity 0.4s ease, transform 0.4s ease;
@starting-style {
opacity: 0;
transform: translateX(40px);
}
}
🌐 Browser Compatibility (Baseline 2024)
Both @starting-style and transition-behavior: allow-discrete are part of Baseline 2024 Widely Available:
| Browser | Supported Version |
|---|---|
| Chrome / Edge | 117+ ✅ |
| Safari | 17.5+ ✅ |
| Firefox | 129+ ✅ |
For older browser fallbacks, use @supports:
@supports (transition-behavior: allow-discrete) {
/* Enhanced modern transitions */
}
🎯 60-Second Viewer Coding Challenge
How would you make a modal scale in from 90% (0.9 → 1.0) on open, but slide down 20px as it closes?
- Grab the spoiler-free starter HTML from our GitHub Code Vault.
- Write your pure CSS solution (zero JS reflow hacks!).
- Drop your solution in the YouTube video comments - the top 3 best solutions will be pinned and inducted into our Community Hall of Fame! 🏆
📦 Resources & Links
- 📺 Watch Full Explainer Video: YouTube Deep-Dive
- ⭐ GitHub Repository:
muneebali500/cascadedev-code-vault - 📄 High-Res Printable Cheat Sheet: Available inside the GitHub repo (
cheat-sheet.png)
Comments
No comments yet. Start the discussion.