This is sort of a known behavior with Chrome. Firefox does seem to be able to handle the removal of animation smoothly with transition but Chrome doesn't do so. I had seen this behavior happen earlier also in this thread.
Why does removal of an animation not work with transition in Chrome?
While I cannot provide a 100% fool-proof explanation of why this happens, we can decode it to some extent based on this HTML5Rocks article about Accelerated rendering in Chrome and this one about GPU accelerated compositing in Chrome.
What seems to happen is that the element gets its own rendering layer because it has explicit position property set on it. When a layer (or part of it) gets invalidated due to animation, Chrome only repaints that layer which is affected by the change. When you open the Chrome Developer Console, switch on "Show Paint Rects" option, you would see that when the animation is happening Chrome only paints the actual element that is getting animated.
However, at the start and end of animation a whole page repaint is happening which puts the element back into its original position immediately and thus overriding the transition behavior.
$('button').click(function(){
$('div').toggleClass('clicked');
});
div{
background-color: #ccc;
height: 100px;
width: 100px;
transition-property: top, left;
transition-duration: 1s;
transition-timing-function: linear;
position: relative;
top: 0;
left: 0;
}
.clicked{
animation-name: clicked;
animation-duration: 1s;
animation-timing-function: linear;
animation-fill-mode: forwards;
}
@keyframes clicked{
0% {top: 0; left: 0;}
100% {top: 100px; left: 100px;}
}
<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>
<button type="button">Click Me!</button>
<div></div>
What is the solution?
Since your movement is actually a linear movement from one position to another, you can achieve it without the need for any animation. All that we need to do is use a translate
transform and shift the element by the required no. of pixels when the class is toggled on. Since there is a transition assigned to the element via another selector, shifting would happen in a linear way. While class is toggled off, the element moves back to its original position again in a linear way due to transition on the element.
$('button').click(function() {
$('div').toggleClass('clicked');
});
div {
background-color: #ccc;
height: 100px;
width: 100px;
transition-property: transform;
transition-duration: 1s;
transition-timing-function: linear;
position: relative;
top: 0;
left: 0;
}
.clicked {
transform: translate(100px, 100px);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<button type="button">Click Me!</button>
<div></div>