Reputation: 691
Tested in Google Chrome 73 (Official Build) (64-bit).
Also tested in latest stable Mozilla, Opera and Safari.
Looks like it is a bug of Chrome only. Hope there is a workaround until the Chrome team fix the bug.
I have created Codepen to show the problem.
const div = document.querySelector('div');
const cssTransition = 2500;
const states = [
['INITIAL', 'translate(0)', cssTransition / 2],
['A', 'translate(0, 100px)', cssTransition + 500],
['B', 'translate(100px, 100px)', cssTransition / 2],
];
let cursor = 0;
const animate = () => {
cursor = (cursor + 1) % states.length;
const [name, value, delay] = states[cursor];
setTimeout(() => {
div.innerText = name;
div.style.transform = value;
animate();
}, delay);
};
animate();
div {
width: 100px;
height: 100px;
background: brown;
color: white;
font-size: 25px;
font-family: sans-serif;
text-align: center;
line-height: 100px;
margin: 50px auto;
transition: 2.5s ease;
}
<div>INITIAL</div>
Animate element via JavaScript to change its position on the screen using CSS3 transform property.
Conditions:
The problem is - transition is not smooth because new animation jumps from initial position of previous animation instead of smooth transition from current location.
When CSS transform property of an element is changed during transition (i.e. before current animation finished) the next animation starts from the initial state of previous animation.
As you can see, animation jumps to INITIAL state which is wrong (undesired). Position at step 6 should be near step 3.
CSS transform property change should reset internal animation timer to 0 (so, new animation will last as defined in transition property) but keep current transform state as initial state for the next animation.
As you can see, new animation starts exactly where it is expected - from step 3 and nicely move element to the new position.
Thanks for reading. Looking forward for your help.
Upvotes: 16
Views: 2537
Reputation: 3408
I am unsure why it happens but a solution would be to manually set the transitioned property (here transform
) to its currently computed value, right before changing to the new desired one.
div.style.transform = getComputedStyle(div).transform;
// Cause a reflow to force the browser to apply the set transform
div.innerWidth;
div.style.transform = value;
Here is a fork of your pen including the fix.
getComputedStyle
is widely supported so you don't need to worry about a polyfill unless you want to support IE < 9
Upvotes: 3