Home > database >  Switch from top/left positioning to transition equivalent without layout jank
Switch from top/left positioning to transition equivalent without layout jank

Time:09-06

I have a div that is positioned using top and left properties. And I need to dynamically switch the positioning from top/left to its transform equivalent. The problem is that when I apply top: 0, left: 0 and equivalent transform property, the div jumps to 0,0 for a split second, before positioning correctly. I understand that changing top and left properties triggers layout redraw.

Here is a example of this behaviour: codepen. When applying Animation1 for the first time the described problem occurs, but it then works as expected after that.

<div  style="left: 120px; top: 100px;"></div>
<div >120,100</div>
<div >270,180</div>
<button onclick="animate1()">Animate1</button>
<button onclick="animate2()">Animate2</button>
function animate1() {
  let div = document.querySelector('div');
  div.style.cssText = `
    left: 0px;
    top: 0px;
    transform: translate(120px, 100px) translate(150px, 80px);`;
}
function animate2() {
  let div = document.querySelector('div');
  div.style.left = `0px`;
  div.style.top = `0px`;
  div.style.transform = `translate(120px, 100px)`;
}
div {
  width: 100px;
  height: 100px;
}
.red {
  background-color: red;
  transform-origin: 50% 50%;
  transition: transform 2s;
  position: absolute;
}
.border {
  border: 1px solid blue;
  position: fixed;
}
.original {
  left: 120px;
  top: 100px;
}
.moved {
  left: 270px;
  top: 180px;
}

Is there a way to prevent this from happening? I tried applying top/left and transform properties in separate requestAnimationFrames and using translate3d without any luck.

CodePudding user response:

You need to set in the css what the starting state is and then change only the transform property.

function animate1() {
  let div = document.querySelector('div');
  div.style.transform = `translate(120px, 100px) translate(150px, 80px)`;
}
function animate2() {
  let div = document.querySelector('div');
  div.style.transform = `translate(120px, 100px)`;
}
div {
  width: 100px;
  height: 100px;
}
.red {
  background-color: red;
  transform-origin: 50% 50%;
  transition: transform 2s;
  position: absolute;
  left: 0px; top: 0px; 
  transform: translate(120px, 100px);
}
.border {
  border: 1px solid blue;
  position: fixed;
}
.original {
  left: 120px;
  top: 100px;
}
.moved {
  left: 270px;
  top: 180px;
}
<div ></div>
<div >120,100</div>
<div >270,180</div>
<button onclick="animate1()">Animate1</button>
<button onclick="animate2()">Animate2</button>

CodePudding user response:

You are not animating top and left so it's changing them abruptly. You could try transition: all 2s; so that it applies to anything, or transition: top 2s, left 2s, transform 2s; to specify only the properties you are using.

NOTE: Animating non-transform properties can have a negative impact on browser performance so do that with caution, if you can set the original position with just the transform (with top/left 0) you would be better off and your original code would probably work as expected.

  • Related