CSS transition-behavior Property

The transition-behavior property specifies whether transitions will be applied to discrete properties, such as display or visibility.

selector { transition-behavior: allow-discrete; }
normal The default behavior where discrete properties are not transitioned and change instantly.
allow-discrete Enables transitions for discrete properties by delaying the change until the end of the transition duration.

Code Examples

A basic example showing how to transition an element from display none to block using allow-discrete and starting-style.

<style>
.box {
  width: 100px;
  height: 100px;
  background-color: #ff5500;
  display: none;
  opacity: 0;
  transition: display 0.5s allow-discrete, opacity 0.5s;
}
.box.show {
  display: block;
  opacity: 1;
}
@starting-style {
  .box.show {
    opacity: 0;
  }
}
</style>
<button onclick="document.querySelector('.box').classList.toggle('show')">Toggle Box</button>
<div class="box"></div>

An advanced semantic example using the dialog element and transition-behavior to animate the modal and its backdrop.

<style>
#modal {
  border: none;
  padding: 20px;
  background: #ffffff;
  box-shadow: 0 0 10px rgba(0,0,0,0.5);
  opacity: 0;
  transform: scale(0.9);
  transition: 
    display 0.4s allow-discrete, 
    overlay 0.4s allow-discrete, 
    opacity 0.4s, 
    transform 0.4s;
}
#modal:open {
  opacity: 1;
  transform: scale(1);
}
@starting-style {
  #modal:open {
    opacity: 0;
    transform: scale(0.9);
  }
}
#modal::backdrop {
  background-color: rgba(0,0,0,0);
  transition: display 0.4s allow-discrete, overlay 0.4s allow-discrete, background-color 0.4s;
}
#modal:open::backdrop {
  background-color: rgba(0,0,0,0.5);
}
</style>
<button id="openBtn">Open Modern Modal</button>
<dialog id="modal">
  <p>Modern Transition Logic</p>
  <button id="closeBtn">Close</button>
</dialog>
<script>
const modal = document.getElementById("modal");
document.getElementById("openBtn").onclick = () => modal.showModal();
document.getElementById("closeBtn").onclick = () => modal.close();
</script>

Pro Tip

You can include this value directly in the "transition" shorthand property. Instead of writing separate lines, you can use "transition: display 0.5s allow-discrete, opacity 0.5s;" to keep your CSS lean. This is the modern way to handle "display" animations without reaching for a heavy JavaScript library or complex keyframe hacks.

Deep Dive

For a long time, we could not animate properties like "display" because they are "discrete"—meaning they are either on or off with no states in between. Think of a standard light switch versus a dimmer switch. Usually, "display: none" to "display: block" is a hard flip. By setting transition-behavior to "allow-discrete", you are telling the browser to play nice with these properties during a transition. When combined with "@starting-style", the browser can now track the start and end points of an element being added to or removed from the page. This allows the element to stay in the DOM long enough for an exit animation, like a fade-out, to actually finish before the element is hidden.

Best Practices

Always use this property in conjunction with "transition-property" and "transition-duration". It is most effective when handling entry and exit animations for modals, menus, or any element toggling between "display: none" and "display: block". To ensure a smooth exit, make sure the "transition-duration" for your discrete property matches the duration of your visual transitions like opacity or transform.

Common Pitfalls

The biggest mistake is thinking this property works by itself. You still need to explicitly list the discrete property in your "transition-property" list. Also, remember that this property does not create intermediate states for things like "display"; it simply delays the switch until the rest of the transition finishes. If you do not define a duration, the change will still happen instantly.

Accessibility

Animations should be purposeful and not cause distraction. If an element takes too long to disappear from the DOM because of a delayed discrete transition, it might still be clickable or focusable while it is fading out. Keep your durations snappy, typically under 500ms, to ensure the user interface feels responsive and logically consistent for everyone.

Dev Data Table: transition-behavior property

default normal
animatable no
inherited no
experimental no
year_intro 2023
year_standard 2024
js_syntax_1 element.style.transitionBehavior = "allow-discrete";
js_syntax_2 element.style.setProperty("transition-behavior", "allow-discrete");
js_note When manipulating this property in JavaScript, ensure you are targeting browsers that support the transition of discrete properties to avoid silent failures in older environments.
browsers { "Chrome": 117, "Edge": 117, "Firefox": 125, "Safari": 17.4, "Opera": 103, "Chrome Android": 117, "Safari on iOS": 17.4, "Samsung Internet": 24, "Opera Mobile": 78 }
results render here...