Using CSS transitions can be quite fun. But what’s not fun is when you want to transition something that needs to use display:none or visibility:hidden (or really, any non-transitionable property).
For example, let’s say you have a dialog. When the user clicks on the close button, you want the dialog to fade out — a simple transition from opacity:1 to opacity:0. The problem is that the element is still there, even though you can’t see it. There’s the transitionEnd event that you can use in JavaScript to set display:none at that time but that doesn’t help you for browsers that don’t support transitions.
I put together a small little jQuery plug-in called prepareTransition to help out and is available on Github. Feedback is most welcome.
Example Usage
Let’s say you had a dialog that you wanted to hide when someone clicks the close button.
.dialog {
position: absolute;
/* and other dialoggy styles */
}
.is-hidden {
display: none;
}
// and our jQuery:
$(".btn-close").click(function(){
$(".dialog").addClass('is-hidden');
})
Now let’s layer on some CSS transitions.
.dialog {
position: absolute;
/* and other dialoggy styles */
opacity: 1;
transition: opacity 1s; /* don't forget vendor prefixed */
}
.is-hidden {
display: none;
opacity: 0;
}
// and our jQuery:
$(".btn-close").click(function(){
$(".dialog").addClass('is-hidden');
})
In browsers that don’t support transitions, this will still work but for browsers that do support transitions, this doesn’t work. Why is that? The display property ends up removing the element from flow before the animation even starts. Clearly less than ideal.
As mentioned at the beginning of this article, I could remove display: none from is-hidden and then use the transitionEnd event to add it back in but then I don’t have something that works in browsers that don’t support transitions.
The prepareTransition method forces display: block; until the end of the transition. It does this by applying an is-transitioning class to the element and then using the transitionEnd JavaScript event to remove the class from the element.
.dialog {
position: absolute;
/* and other dialoggy styles */
opacity: 1;
transition: opacity 1s;
}
.is-hidden {
display: none;
opacity: 0;
}
.is-transitioning {
display: block !important;
visibility: visible !important;
}
// and our jQuery:
$(".btn-close").click(function(){
$(".dialog").prepareTransition().addClass('is-hidden');
})
Using prepareTransition is a handy way of allowing an easy fallback design for browsers that don’t support transitions while making it easier to manage transitions for browsers that do support it.
Added to the specification
This would be much easier if there was a transitionStart event, though. Then, a method wouldn’t have to be run before applying the is-transitioning class.
Even better would be a pseudo-class that could be applied to an element.
:transition {
display: block !important;
}
Or maybe it’s just assumed that any element in transition should be display: block (and visibility: visible). In any case, we clearly need a little more at the browser implementation level to simplify this use case.