Description of the Current State
An element is hidden using display: none, and when it’s made visible via JavaScript, you might expect it to have a fade-in effect with an opacity transition. However, the transition property doesn’t work in this case.
Here’s an example:
<div id="element" class="element">placeholder</div>
.element {
display: none;
opacity: 0;
transition: .2s;
}
.element.active {
display: block;
opacity: 1;
}
element.classList.add('active');
At this stage, the element appears abruptly rather than fading in with an opacity transition.
To address this, two common methods have been used in the past:
- Make the element visible with an opacity of 0, then change its opacity to 1 in the next render cycle.
- Use a CSS animation. Refer to the following code:
.element.active {
display: block;
animation: fadeIn .2s both;
}
@keyframes {
from { opacity: 0; }
to { opacity: 1; }
}
However, the two methods above are a bit inconvenient compared to simply using a transition property.
So, is there a simpler way to add animation when transitioning an element from display: none to display: block?
Yes, there is! Modern browsers have recently introduced a new CSS property called transition-behavior, which can meet this need.
Introduce to transition-behavior
The syntax is as follows:
transition-behavior: allow-discrete;
transition-behavior: normal;
Among them:
- allow-discrete allows discrete CSS properties to support transition effects, with the display property being the most representative example.
- normal refers to the previous transition behavior, where, except for visibility (which I have always considered a discrete CSS property), other discrete properties did not support transition effects.
Usage example: You can use the transition property to achieve a transition effect between display:inline ↔ none.
Here is the HTML:
<button id="trigger">show or hide image</button>
<img id="target" src="https://raw.githubusercontent.com/trevortylerlee/n1/main/n1.jpeg" />
Using the toggle of the hidden attribute to achieve visibility changes:
trigger.onclick = function () {
target.toggleAttribute('hidden');
};
OK, now for the most important CSS—it’s really simple, and can be done with just a few lines of code:
img {
transition: .25s allow-discrete;
opacity: 1;
}
img[hidden] {
opacity: 0;
}
Awesome!
Of course, the CSS code above can also be written separately:
transition-duration: .25s;
transition-behavior: allow-discrete;
However, when clicking the button again, expecting it to fade out, there is no fade-out effect.
Problem Analysis and Solution
Why does setting transition-behavior: allow-discrete allow the display: none transition to be visible after the transition duration ends, making the opacity transition visible to the naked eye?
However, the transition from display: none to display: block appears suddenly. This is because, in the browser’s rendering process, the change from display: none to display: block and the opacity change to 1 happen in the same render frame. Since there’s no initial opacity, you don’t see the animation effect.
So, is there a way to make the display change with a transition effect?
Using the @starting-style Rule to Declare the Transition Starting Point
As the name suggests, @starting-style is used to declare the starting style, specifically for transition effects.
For example, to achieve a fade-in effect when the element is displayed, it’s simple—just add three more lines of code:
img {
transition: .25s allow-discrete;
opacity: 1;
@starting-style {
opacity: 0;
}
}
Alternatively, you can write it like this without using CSS nesting syntax:
img {
transition: .25s allow-discrete;
opacity: 1;
}
@starting-style {
img {
opacity: 0;
}
}
At this point, when we click the button to display the image, we can see it fade in with a transparency animation, as shown below.
CSS is becoming more powerful.
This article introduces two key concepts: first, transition-behavior: allow-discrete, which allows elements with display: none to have a fade-out effect; and second, the @starting-style rule, which enables elements to transition from display: none with a fade-in effect.
In practical web development, popovers (floating layers) and dialog boxes are often toggled based on the display property.
With the introduction of transition-behavior and @starting-style, the interactivity of these native HTML elements has been significantly enhanced, addressing long-standing limitations. It’s truly exciting—CSS is definitely becoming more powerful.
To stay updated on the latest CSS properties and their applications, be sure to follow me