一尘不染

如果元素开始隐藏,css过渡将不起作用

css

我有2 div秒,其中一个通过隐藏display:none;。两者在属性上具有相同的CSS过渡right

如果我right通过JQuery
更改属性并div通过使用$.css('display','none')$.show()或其他$.toggle()方式显示hidden
,则隐藏的div会立即在结束位置绘制

$('button').on('click',function(){

  $('.b').show();

  $('.b').css('right','80%');

  $('.a').css('right','80%');

})


body {

  width:800px;

  height:800px;

}



div {

  width:50px;

  height:50px;

  background-color:#333;

  position:absolute;

  display:none;

  right:5%;

  top:0;

  transition:right .5s cubic-bezier(0.645, 0.045, 0.355, 1);

  color: white;

}



.a {

  display:block;

  top:60px;

}


<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class='a'>A

</div>

<div class='b'>B

</div>

<button>Launch</button>

如果我使用$.animate()它将起作用。但是我的问题是; 这是错误还是正常行为?

编辑 不是显示上的过渡的重复:属性会导致这里的问题不是关于显示属性的动画或可见性


阅读 505

收藏
2020-05-16

共1个答案

一尘不染

要清楚地了解情况,您需要了解CSSOM和DOM之间的关系。

在先前的Q / A中,我对 重绘 过程的工作方式进行了一些开发。 基本上,有三个步骤,DOM操作,重排和绘制。

  • 第一个( DOM操作 )只是修改js对象,并且都是同步的。
  • 第二个( reflow ,又称 layout )是我们感兴趣的一个,并且稍微复杂一些,因为只有某些DOM方法和绘画操作需要它。它包括更新所有CSS规则并重新计算页面上每个元素的所有计算样式。
    作为一项相当复杂的操作,浏览器将尝试尽可能少地执行此操作。

  • 第三次( 绘画 )最多每秒最多只能完成60次(仅在需要时)。


CSS过渡通过从一种状态过渡到另一种状态来工作。为此,他们查看元素的 最后一个计算值 以创建初始状态。
由于浏览器仅在需要时才重新计算所计算的样式,因此在过渡开始时,您应用的所有DOM操作均无效。

因此,在您的第一种情况下,当计算过渡的初始状态时,

.b { computedStyle: {display: none} }

…就是这样。

因为,是的,这display: none就是CSSOM的强大功能。如果元素具有display: none,则不需要绘制它,则它不存在。

因此,我什至不确定转换算法是否会启动,但是即使这样,初始状态对于 任何可 转换值也将是无效的,因为所有计算出的值都为null。

.a从一开始就可见您的元素没有此问题,可以进行过渡。

如果你能使其与延迟(诱导工作$.animate),这是因为DOM MANIP“这确实改变之间的display财产,这种延迟DOM
MANIP的执行”,做触发转换,浏览器确实触发一个 回流 (例如,因为屏幕之间出现了 垂直 同步,并且启动了 绘画 操作)。


现在,这不是问题的一部分,但是由于我们确实了解发生了什么,因此我们也 可以更好地控制它

实际上,某些DOM方法确实需要具有最新的计算值。举例来说Element.getBoundingClientRect,或element.offsetHeightgetComputedStyle(element).height等等。所有这些需要
整个页面 已经更新,以便拳击正确做出的计算值(例如一个元素可以有一个保证金推或多或少等)。

这意味着我们不必在的时候,浏览器将触发这个未知的 回流 ,我们可以迫使它这样做时,我们想要的。

但是请记住, 页面上的所有元素都 需要更新,这不是一个小操作,如果浏览器宽容地这样做,这是有充分理由的。

因此,最好偶尔使用它,每帧最多使用一次。

幸运的是,WebAPI使我们能够在绘画操作发生之前钩住一些js代码:requestAnimationFrame。

因此,最好的方法是在此预绘画回调中仅强制执行一次重排,并从该回调中调用需要更新值的所有内容。

$('button').on('click',function(){

  $('.b').show(); // apply display:block synchronously



  requestAnimationFrame(() => { // wait just before the next paint

    document.body.offsetHeight; // force a reflow

    // trigger the transitions

    $('.b').css('right','80%');

    $('.a').css('right','80%');

  });

})


body {

  width:800px;

  height:800px;

}



div {

  width:50px;

  height:50px;

  background-color:#333;

  position:absolute;

  display:none;

  right:5%;

  top:0;

  transition:right .5s cubic-bezier(0.645, 0.045, 0.355, 1);

  color: white;

}



.a {

  display:block;

  top:60px;

}


<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class='a'>A

</div>

<div class='b'>B

</div>

<button>Launch</button>

但老实说,设置起来并不总是那么容易,因此,如果您确定某些东西会偶尔被触发,那么您可能会很懒惰并同步执行所有操作:

$('button').on('click',function(){

  $('.b').show(); // apply display:block

  document.body.offsetHeight; // force a reflow

  // trigger the transitions

  $('.b').css('right','80%');

  $('.a').css('right','80%');

})


body {

  width:800px;

  height:800px;

}



div {

  width:50px;

  height:50px;

  background-color:#333;

  position:absolute;

  display:none;

  right:5%;

  top:0;

  transition:right .5s cubic-bezier(0.645, 0.045, 0.355, 1);

  color: white;

}



.a {

  display:block;

  top:60px;

}


<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class='a'>A

</div>

<div class='b'>B

</div>

<button>Launch</button>
2020-05-16