files/en-us/web/css/reference/properties/transition-behavior/index.md
The transition-behavior CSS property specifies whether transitions will be started for properties whose animation behavior is discrete.
/* Keyword values */
transition-behavior: allow-discrete;
transition-behavior: normal;
/* Global values */
transition-behavior: inherit;
transition-behavior: initial;
transition-behavior: revert;
transition-behavior: revert-layer;
transition-behavior: unset;
allow-discrete
normal
The transition-behavior property is only relevant when used in conjunction with other transition properties, notably {{cssxref("transition-property")}} and {{cssxref("transition-duration")}}, as no transition occurs if no properties are animated over a non-zero duration of time.
.card {
transition-property: opacity, display;
transition-duration: 0.25s;
transition-behavior: allow-discrete;
}
.card.fade-out {
opacity: 0;
display: none;
}
The transition-behavior value can be included as part of a shorthand {{cssxref("transition")}} declaration. When included in the shorthand, when using or defaulting to all properties, the allow-discrete value has no impact on regular animatable properties. The following CSS is equivalent to the longhand declarations above:
.card {
transition: all 0.25s;
transition: all 0.25s allow-discrete;
}
.card.fade-out {
opacity: 0;
display: none;
}
In the above snippet we include the transition property twice. The first instance does not include the allow-discrete value — this provides cross-browser support, ensuring the card's other properties still transition in browsers that don't support transition-behavior.
Discrete-animated properties generally flip between two values 50% through animating between the two.
There is an exception, however, which is when animating to or from display: none or content-visibility: hidden. In this case, the browser will flip between the two values so that the transitioned content is shown for the entire animation duration.
So for example:
display from none to block (or another visible display value), the value will flip to block at 0% of the animation duration so it is visible throughout.display from block (or another visible display value) to none, the value will flip to none at 100% of the animation duration so it is visible throughout.{{cssinfo}}
{{CSSSyntax}}
In this example, a popover is animated as it transitions from hidden to shown and back again.
The HTML contains a {{htmlelement("div")}} element declared as a popover using the popover attribute, and a {{htmlelement("button")}} element designated as the popover's display control using its popovertarget attribute.
<button popovertarget="mypopover">Show the popover</button>
<div popover="auto" id="mypopover">I'm a Popover! I should animate.</div>
html {
font-family: "Helvetica", "Arial", sans-serif;
}
[popover] {
font-size: 1.2rem;
padding: 10px;
}
[popover]:popover-open {
opacity: 1;
transform: scaleX(1);
}
[popover] {
/* Final state of the exit animation */
opacity: 0;
transform: scaleX(0);
transition-property: opacity, transform, overlay, display;
transition-duration: 0.7s;
transition-behavior: allow-discrete;
/* Using the shorthand transition property, we could write:
transition:
opacity 0.7s,
transform 0.7s,
overlay 0.7s allow-discrete,
display 0.7s allow-discrete;
or even:
transition: all 0.7s allow-discrete;
*/
}
/* Needs to be included after the previous [popover]:popover-open
rule to take effect, as the specificity is the same */
@starting-style {
[popover]:popover-open {
opacity: 0;
transform: scaleX(0);
}
}
The two properties we want to animate are {{cssxref("opacity")}} and {{cssxref("transform")}}: we want the popover to fade in and out while growing and shrinking in the horizontal direction. We set a starting state for these properties on the default hidden state of the popover element (selected via [popover]), and an end state on the open state of the popover (selected via the {{cssxref(":popover-open")}} pseudo-class). We then set a {{cssxref("transition")}} property to animate between the two.
Because the animated element is being promoted to the top layer when shown and removed from the top layer when hidden — which also means that its hidden state has display: none set on it — the following properties are added to the list of transitioned elements to get the animation working in both directions. In both cases, transition-behavior: allow-discrete is set in the shorthand to enable discrete animation.
display: Required so that the animated element is visible (set to display: block) throughout both the entry and exit animation. Without this, the exit animation would not be visible; in effect, the popover would just disappear.In addition, a starting state for the animation is set inside the {{cssxref("@starting-style")}} at-rule. This is needed to avoid unexpected behavior. By default transitions are not triggered on elements' first style updates, or when the display type changes from none to another type. @starting-style allows you to override that default in a specific controlled fashion. Without this, the entry animation would not occur and the popover would just appear.
The code renders as follows:
{{ EmbedLiveSample("Transitioning a popover", "100%", "200") }}
[!NOTE] Because popovers change from
display: nonetodisplay: blockeach time they are shown, the popover transitions from its@starting-stylestyles to its[popover]:popover-openstyles every time the entry transition occurs. When the popover closes, it transitions from its[popover]:popover-openstate to the default[popover]state.It is possible for the style transition on entry and exit to be different in such cases. See our Demonstration of when starting styles are used example for a proof of this.
{{Specifications}}
{{Compat}}