同时改变宽度、高度和变换会导致奇怪的过渡

Posted

技术标签:

【中文标题】同时改变宽度、高度和变换会导致奇怪的过渡【英文标题】:Changing both width, height and transform simultaneously cause the weird transition 【发布时间】:2021-10-01 11:27:24 【问题描述】:

如果我同时更改widthheighttransform 属性,它会产生非常奇怪的过渡。示例如下。查看矩形及其相对于红线的位置。

The demo.

我知道将transform 属性替换为lefttop 属性可以解决此问题,但这不是我的解决方案,因为它会产生性能和其他问题。

更新:scale 转换不是解决方案,因为在实际情况下可以更改比例并且内部内容不应受到比例转换的影响。 ——

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>

【问题讨论】:

您的demo 中没有发生奇怪的transitionPreview。您能否提供重现此行为的步骤? 我可以通过多次切换状态来重现它。从一个渲染到下一个渲染似乎不一致。有时它看起来很好,有时它看起来像问题中的动画 gif。 @nitrovatter 如果可能的话,我会重新考虑转换 lefttop 值而不是 transform: translate() 如果变换“摆动”是不可接受的,但您仍然需要为某些原因。或者,看看您是否可以使@ЖнецЪ 的方法起作用,这可能是我解决问题的方式。 【参考方案1】:

试试这个例子,我确实使用了transform: scale 而不是transform: translate。上移了small-box,因为如果缩放box 本身,small-box 也会缩放。并且确实换成了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>

【讨论】:

感谢您的回答,但我确实应该指出:scale 不是解决方案,因为在实际情况下可以更改比例。此外,内部内容的比例不应改变。 唉,在你的例子中,盒子的位置丢失了。这一点很重要。位置可能非常多样化。【参考方案2】:

我在 js 上更改 transform 属性:50px100px 变为 calc(300px - 50%)

calc(300px - 50%) 是行位置减去.box 的 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>

【讨论】:

非常感谢,它成功了。你是怎么想到这个主意的? 我第一次尝试使用变量并更改.box的来源,然后迷路了,天才中风 太棒了。再次感谢。

以上是关于同时改变宽度、高度和变换会导致奇怪的过渡的主要内容,如果未能解决你的问题,请参考以下文章

组合大小和翻译过渡会导致 Safari 卡顿

在 UIImageView 上设置顶部约束会导致 UILabel 固定高度

Android:当视图改变方向时切换高度和宽度

div中心的CSS过渡宽度和高度

改变 LinearLayout 的背景会改变它的宽度和高度

如何根据另一个视图的高度/宽度按比例设置视图高度/宽度?