CSS3 animations - animationstart event won't fire when using transition:
TL;DR (Short Answer):
As of now there is no event that gets fired during the start of a transition. Transitions always happen only when a triggering condition is satisfied and so the event which triggers the transition can roughly be considered as equivalent to the transitionstart
event.
In the below snippet, I have added a user-defined function (transitionStart
) which gets called right after the .addClass('slide')
and this is kind of equivalent to transitionstart
.
/* For Animation Start */
setTimeout(function() {
$('.animated').removeClass('hide').addClass('slide');
}, 1000);
$('.animated').bind('animationstart webkitAnimationStart', function() {
console.log('Animation Started');
});
/* For Transition Start */
setTimeout(function() {
$('.animated').removeClass('hide').addClass('slide');
transitionStart();
}, 1000);
function transitionStart(){
console.log('Transition Started');
}
.element {
padding: 10px;
background-color: #ccc;
width: 100px;
height: 100px;
}
.element.animated.hide {
display: none;
}
.animated.slide {
animation: slide 1s infinite
}
@keyframes slide {
from {
transform: translateX(0);
}
to {
transform: translateX(-100px);
}
}
.element.transitioned.hide {
transform: translateX(-100%);
}
.transitioned.slide {
transition: all 2s ease-in 0s;
transform: translateX(200%);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3>Element with Animation</h3>
<div class='element hide animated'>
box
</div>
<h3>Element with Transition</h3>
<div class='element hide transitioned'>
box
</div>
A transitionend
event is available and can be used to identify the ending point of the transition and then perform any required function calls or other process. The below snippet has a sample for this.
setTimeout(function() {
$('.transitioned').removeClass('hide').addClass('slide');
transitionStart();
}, 1000);
function transitionStart(){
console.log('Transition Started');
}
$('.transitioned').bind('transitionend', function() {
console.log('Transition Ended');
});
.element {
padding: 10px;
background-color: #ccc;
width: 100px;
height: 100px;
}
.element.transitioned.hide {
transform: translateX(-100%);
}
.transitioned.slide {
transition: all 2s ease-in 0s;
transform: translateX(200%);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3>Element with Transition</h3>
<div class='element hide transitioned'>
box
</div>
Long Answer:
First of all, animation
and transition
are not same even though they produce a gradual change of the values assigned to the properties. Below are some key differences:
- Transitions can have only one start state and one end state. Intermediate states are beyond the control of a developer and is determined by the UA. When using animations, the developer can specify as many intermediate states between the start and end state as required.
- Transitions cannot start/be triggered automatically unlike animations. Transitions are started only when there is a change of state through user interaction like (
hover
,click
etc) or when some extra class is added to the element through JS. Animations can start automatically when the page is loaded. - There is no looping or iteration for transitions (unlike animations). A transition can run only once.
You can read more about the differences between them and when one should be used in this article.
Animation events (animationstart
, animationend
etc) will not fire for your first case (the one where you are using transition
) because there is no animation
or valid @keyframe
rule specified on the element.
As per W3C Spec
Any animation for which both a valid keyframe rule and a non-zero duration are defined will run and generate events; this includes animations with empty keyframe rules.
As per current spec there is no specific event that is fired when a transition
is started unlike when an animation
starts. In other words, there is no transitionstart
event. Currently there is only one transition event (transitionend
) that is implemented. (W3C Spec).
I cannot say for sure if it was a conscious decision to not implement transitionstart
event or it was just a miss. But the fact is that we don't have an equivalent one at present.
Personally, I do not see this as a big miss because the developer should know the exact trigger points for a transition
(like the addition of a new class via JS or through user interaction events which can also be detected via JS). So, we can always say that a transition has started at the very same instant when the trigger condition was satisfied. For your case, the transition
has started at the same time at which the .addClass('slide')
is executed. So, whatever extra steps you want to do (or) functions that you want to call can be called directly after the .addClass('slide')
is executed.
Points to note:
- The above way of finding a transition's start is not 100% equivalent to the
animationstart
event. The reason is because theanimationstart
event is fired only after theanimation-delay
that is set has expired. In your snippet there is no delay for either the animation or transition and hence this is not a big issue. If you do have a delay then you'd have to get the value of thetransition-delay
property and execute another time-out before calling the required functions (or) actions. - I remember reading earlier in another article that IE10 had
transitionstart
event but it is non-standard and hence is not recommended.
Now in 2020:
When using transitions, you have to use transition
events instead of animation
events.
Compatability table (works even in Edge v42)
yourElement.addEventListener("transitionstart", () => {
alert("transitionstart");
});
Example:
const div1 = document.querySelector(".div1");
div1.addEventListener("click", () => {
div1.classList.toggle("transition");
});
div1.addEventListener("transitionstart", () => {
console.log("transitionstart");
});
.div1{
transition: transform 1s ease-in-out;
background-color: darkseagreen;
display:inline-block;
}
.div1.transition{
transform: translateX(100px);
}
.div1.transition:after{
content: " again, when transition stopps!";
background-color: yellow;
}
<div class="div1"> CLICK ME</div>