How to detect via js if any sort of transition is being applied to the element right now?
-
When your problem includes any specific browser, and the words "goes crazy and stops working" I don't know that there is a pretty solution... – Ryan Jan 15 '13 at 23:33
-
the specifics of the problem is not really an issue, and it's on all browsers.. i just gave a very specific example for the curios folks, but my question stands and it's something I would like to know even if I hadn't faced a problem. – vsync Jan 15 '13 at 23:45
-
I know, I was just giving you a hard time. I would actually like to know as well. I've run into problems with css-transitions before, as is evidenced by this question: http://stackoverflow.com/questions/7288977/element-style-display-none-not-working-in-firefox-but-is-in-chrome – Ryan Jan 15 '13 at 23:48
3 Answers
You can use the Web Animation API for that, notably the Element#getAnimations
method, which will return a list of Animation objects applied on the Element. These will include Web Animations (from .animate()
), CSS @keyframes
animations, and CSS transitions.
document.querySelectorAll("a").forEach((el) => {
el.onmouseenter = (evt) => {
const animations = el.getAnimations(); // we could also ask to look in the subtree
// we're only interested in CSS transitions
const transitions = animations.filter((anim) => anim instanceof CSSTransition);
console.log(transitions.length
? transitions.map((anim) => anim.transitionProperty )
: "no transition"
);
};
});
a:hover {
color: red;
opacity: 0.5;
}
.color-transition {
transition: color 1s;
}
.color-and-opacity-transition {
transition: color 1s, opacity 5s;
}
/*SO-only*/.as-console-wrapper { max-height: 110px !important }
<b>Hover these anchors to log their applied transitions.</b><br>
<a class="color-transition">color transition</a><br>
<a class="color-and-opacity-transition">color & opacity transition</a><br>
<a>no transition</a>

- 123,334
- 13
- 219
- 285
You can listen to transitionstart
, transitionend
, and, transitioncancel
events. To tell if some element is under transition. However, you cannot know if some element will start a transition (even if it has transition-delay: 0s
) using this code:
/** @type {Map<HTMLElement, number>} */
const transitionCounter = new Map();
/** @type {(() => void)[]} */
const waitingTransition = [];
const incReference = (counter, target) => {
if (counter.has(target)) {
counter.set(target, counter.get(target) + 1);
} else {
counter.set(target, 1);
}
};
const desReference = (counter, target) => {
if (!counter.has(target)) {
return;
} else if (counter.get(target) === 1) {
counter.delete(target);
} else {
counter.set(target, counter.get(target) - 1);
}
};
document.addEventListener('transitionstart', event => {
const { target } = event;
incReference(transitionCounter, target);
const onFinish = event => {
if (event.target !== target) return;
desReference(transitionCounter, target);
target.removeEventListener('transitioncancel', onFinish);
target.removeEventListener('transitionend', onFinish);
[...waitingTransition].forEach(listener => { listener(); });
};
target.addEventListener('transitioncancel', onFinish);
target.addEventListener('transitionend', onFinish);
});
/**
* @param {HTMLElement} element
* @returns {boolean}
*/
const isUnderTransition = function (element) {
const parents = [];
for (let i = element; i; i = i.offsetParent) parents.push(i);
return Array.from(transitionCounter.keys()).some(running => parents.includes(running));
};
/**
* @param {HTMLElement} element
* @returns {Promise<void>}
*/
const waitTransitionEnd = async function (element) {
if (!isUnderTransition(element)) return Promise.resolve();
return new Promise(resolve => {
waitingTransition.push(function listener() {
if (isUnderTransition(element)) return;
waitingTransition.splice(waitingTransition.indexOf(listener), 1);
resolve();
});
});
};

- 4,263
- 5
- 28
- 47
As specified by W3C Editor's Draft - CSS Transition
The ‘transitionend’ event occurs at the completion of the transition. In the case where a transition is removed before completion, such as if the transition-property is removed, then the event will not fire.
So, I think there's not a valid simple way to solve this problem. The solution is left to the implementation (the browser) which decide if it does or doesn't render the transition at all.
Maybe, a solution could be to attach a listener to the element that fires the transition and after a specific elapsed time it checks if the transitioned element has the required CSS attributes set, and if those attributes aren't set as expected you can run your function by yourself.

- 2,328
- 2
- 21
- 31
-
yes I've thought about using some setTimeout method but..it's just ugly. i'm very surprised there is no "ongoingTransition" flag in the W3C draft or something of the sort. – vsync Jan 16 '13 at 00:13
-
yes, it's a big limit, I hope when they will reach the final specifications, more events will be available. But currently, I guess the only way is to rely on custom timed functions which simulate the missing event callbacks. – Ragnarokkr Jan 16 '13 at 00:26
-
that means synchronizing the timing of the CSS and the JS manually..tedious. – vsync Jan 16 '13 at 00:59