My current approach involves using a clever method to delay the transition of visibility, in combination with opacity. So far, everything is working smoothly:
<body>
<button>run</button>
<div class="box"></div>
</body>
.box {
visibility: hidden;
opacity: 0;
/* property name | duration | easing function | delay */
transition: visibility 0s ease-in-out 3s,
opacity 3s ease-in-out;
}
.box.show {
visibility: visible;
opacity: 1;
transition-delay: 0s;
}
An issue arises when trying to monitor the transitionend
event. The goal is to log both the visibility
and opacity
properties, but only the opacity
gets logged (view pen here):
const button = document.querySelector('button');
const box = document.querySelector('.box');
// When class "show" is added, only "opacity" is logged
// When class "show" is removed, both "opacity" and "visibility" are logged
box.addEventListener('transitionend', e => {
console.log(e.propertyName);
});
button.addEventListener('click', () => {
box.classList.toggle('show');
});
Why do I need to listen to transitioned
? This event allows me to check the number of transition properties (totalProperties
). By tracking all properties that are transitioned (using a counter
), I can determine when the element has completed all its transitions:
const totalProperties = window.getComputedStyle(element)['transition-property'].split(',').length;
let counter = 0;
const callback = e => {
e.stopPropagation();
if (++counter === totalProperties) {
counter = 0;
box.removeEventListener('transitionend', callback);
console.log('All properties transitioned.');
}
};
box.addEventListener('transitionend', callback);