Changing both width, height and transform simultaneously cause the weird transition

Viewed 432

If I change the width, height and transform properties simultaneously it produces pretty weird transition. The example is below. Look at the rectangle and its position relative to the red line.

The demo.

enter image description here

I know replacing transform property by left and top properties fix it, but it's not the solution in my case because it produces performance and other issues.

UPDATE: the scale transform is not solution, because in the real case proportions can be changed and the internal content should not be affected by scale transformation. –

const states = [{
    height: '250px',
    width: '500px',
    transform: 'translate(50px, 50px)'
  },
  {
    height: '150px',
    width: '250px',
    transform: 'translate(175px, 100px)'
  },
]

let currentState = 0;

function updateState() {
  const box = document.querySelector(".box");

  const state = states[currentState];

  currentState = (currentState + 1) % states.length

  box.style.height = state.height
  box.style.width = state.width
  box.style.transform = state.transform
}
.button {
  position: absolute;
  top: 0;
  left: 0;
}

.box {
  transition: 0.4s ease-in-out;
  position: absolute;
  background: #AAA;
  left: 0;
  top: 0;
}

.line {
  position: absolute;
  left: 300px;
  height: 100%;
  background: red;
  width: 1px;
}

.small-box {
  width: 10px;
  height: 10px;
  border: solid 1px black;
  position: absolute;
  transform: translateX(-50%);
}
<div class="box">
  <div class="small-box" style="left: 50%; top:0"></div>
</div>
<div class="line"></div>
<button class="button" onclick="updateState()">Update State</button>

2 Answers

Try this example i did use transform: scale instead transform: translate. Moved up the small-box, because if scaled the box itself, small-box is scaled too. And did wrap into flex.

const states = [
  {
    height: '250px',
    width: '500px',
    // transform: 'translate(50px, 50px)',
  },
  {
    height: '150px',
    width: '250px',
    // transform: 'translate(175px, 100px)',
  },
];

let currentState = 0;

function updateState() {
  const box = document.querySelector('.box');

  const state = states[currentState];

  currentState = (currentState + 1) % states.length;

  box.style.height = state.height;
  box.style.width = state.width;
  box.style.transform = state.transform;
}
.wrapper { /* Added */
  width: 600px;
  height: 300px;
  position: relative;
  border: 1px solid red;
  display: flex;
  justify-content: center;
  align-items: flex-start;
}
.button {
  position: absolute;
  top: 0;
  left: 0;
}

.box {
  transition: 0.4s ease-in-out;
  /* position: absolute; */
  background: #aaa;
  /* left: 0; */
  /* top: 0; */
  transform-origin: top center;
}
.line {
  position: absolute;
  left: 50%; /* Changed */
  height: 100%;
  background: red;
  width: 1px;
}
.small-box {
  width: 10px;
  height: 10px;
  border: solid 1px black;
  position: absolute;
  transform: translateX(-50%); /* Added */
}
<div class="wrapper">
  <div class="box">
    <div class="small-box" style="left: 50%; top: 0"></div>
  </div>
  <div class="line"></div>
  <button class="button" onclick="updateState()">Update State</button>
</div>

I change transform property on js : 50px and 100px is become calc(300px - 50%)

calc(300px - 50%) is line position minus half of .box's div

const states = [{
    height: '250px',
    width: '500px',
    transform: 'translate(calc(300px - 50%), 50px)'
  },
  {
    height: '150px',
    width: '250px',
    transform: 'translate(calc(300px - 50%), 100px)'
  },
]

let currentState = 0;

function updateState() {
  const box = document.querySelector(".box");

  const state = states[currentState];

  currentState = (currentState + 1) % states.length

  box.style.height = state.height
  box.style.width = state.width
  box.style.transform = state.transform
}
.button {
  position: absolute;
  top: 0;
  left: 0;
}

.box {
  transition: 0.4s ease-in-out;
  position: absolute;
  background: #AAA;
  left: 0;
  top: 0;
}

.line {
  position: absolute;
  left: 300px;
  height: 100%;
  background: red;
  width: 1px;
}

.small-box {
  width: 10px;
  height: 10px;
  border: solid 1px black;
  position: absolute;
  transform: translateX(-50%);
}
<div class="box">
  <div class="small-box" style="left: 50%; top:0"></div>
</div>
<div class="line"></div>
<button class="button" onclick="updateState()">Update State</button>

Related