You can solve this by adding or removing a class from the object, and then having two sets of CSS transitions - one for the transition in and one for the transition out. They will have both opacity and visibility properties but different delay values, and potentially could have different durations and easing methods too.
Here is some example CSS. I've included only the CSS relevant for the transition, not any descriptive properties about the object itself.
/* fade out */
#hiddenobject {
opacity: 0;
visibility: hidden;
-webkit-transition: opacity 200ms ease 0s, visibility 0s linear 200ms;
-moz-transition: opacity 200ms ease 0s, visibility 0s linear 200ms;
-ms-transition: opacity 200ms ease 0s, visibility 0s linear 200ms;
-o-transition: opacity 200ms ease 0s, visibility 0s linear 200ms;
transition: opacity 200ms ease 0s, visibility 0s linear 200ms;
}
/* fade in */
#hiddenobject.showobject {
opacity: 1;
visibility: visible;
-webkit-transition: opacity 500ms ease-in 0s, visibility 0s linear 0s;
-moz-transition: opacity 500ms ease-in 0s, visibility 0s linear 0s;
-ms-transition: opacity 500ms ease-in 0s, visibility 0s linear 0s;
-o-transition: opacity 500ms ease-in 0s, visibility 0s linear 0s;
transition: opacity 500ms ease-in 0s, visibility 0s linear 0s;
}
In this case we have an object with an ID of 'hiddenobject' which is hidden from view. It has both an opacity of zero and the visibility attribute is hidden. We will add a class of 'showobject' to it, which will cause the item to be displayed, with an opacity of 1 and visibility of visible.
Visibility can only have two states really, it's either visible or it's not - there is no grey area in-between. So to show a fade we need to use the opacity property. The difficulty with opacity is that something with an opacity of 0 will still be present on screen - it can be clicked on, interacted with etc. which may not be desirable. The solution is to use both properties together.
When we add the 'showobject' class we transition the opacity from it's current value of 0 to it's new value of 1 with a duration of 500ms, or half a second. The delay attribute of that transition is set to 0 seconds, so it happens immediately. The visibility of that object was hidden, so in order to witness this fade in we need to immediately transition the visibility property to it's new state of visible. This transition has both a duration and delay of 0s, so it happens instantly - I've put linear easing as there is no need for any easing really, so may as well keep it simple - that's personal preference. So now our object is visible the moment we add the class and we see it fade in.
When we remove the class we want the fade to happen a bit quicker, so our default transition for the object has an opacity duration of 200ms, a fifth of a second. If we changed the visibility to hidden straightaway however we wouldn't see the fade at all, it would just disappear. So we have to delay the transition by a value equal to the length of the fade - in this case 200ms. Now our object completes it's fade to 0 opacity before changing it's visibility to hidden.
The visibility transition on the showobject class is pretty much what would happen with that property by default - an instant change - but we need to define it there to overwrite the delayed transition we've set on the element default.