Search code examples
htmlcsscss-transitionscss-transforms

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


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>


Solution

  • 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>