我有2 div秒,其中一个通过隐藏display:none;。两者在属性上具有相同的CSS过渡right。
div
display:none;
right
如果我right通过JQuery 更改属性并div通过使用$.css('display','none')或$.show()或其他$.toggle()方式显示hidden ,则隐藏的div会立即在结束位置绘制
$.css('display','none')
$.show()
$.toggle()
$('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()它将起作用。但是我的问题是; 这是错误还是正常行为?
$.animate()
编辑 不是显示上的过渡的重复:属性会导致这里的问题不是关于显示属性的动画或可见性
要清楚地了解情况,您需要了解CSSOM和DOM之间的关系。
在先前的Q / A中,我对 重绘 过程的工作方式进行了一些开发。 基本上,有三个步骤,DOM操作,重排和绘制。
第二个( reflow ,又称 layout )是我们感兴趣的一个,并且稍微复杂一些,因为只有某些DOM方法和绘画操作需要它。它包括更新所有CSS规则并重新计算页面上每个元素的所有计算样式。 作为一项相当复杂的操作,浏览器将尝试尽可能少地执行此操作。
第三次( 绘画 )最多每秒最多只能完成60次(仅在需要时)。
CSS过渡通过从一种状态过渡到另一种状态来工作。为此,他们查看元素的 最后一个计算值 以创建初始状态。 由于浏览器仅在需要时才重新计算所计算的样式,因此在过渡开始时,您应用的所有DOM操作均无效。
因此,在您的第一种情况下,当计算过渡的初始状态时,
.b { computedStyle: {display: none} }
…就是这样。
因为,是的,这display: none就是CSSOM的强大功能。如果元素具有display: none,则不需要绘制它,则它不存在。
display: none
因此,我什至不确定转换算法是否会启动,但是即使这样,初始状态对于 任何可 转换值也将是无效的,因为所有计算出的值都为null。
.a从一开始就可见您的元素没有此问题,可以进行过渡。
.a
如果你能使其与延迟(诱导工作$.animate),这是因为DOM MANIP“这确实改变之间的display财产,这种延迟DOM MANIP的执行”,做触发转换,浏览器确实触发一个 回流 (例如,因为屏幕之间出现了 垂直 同步,并且启动了 绘画 操作)。
$.animate
display
现在,这不是问题的一部分,但是由于我们确实了解发生了什么,因此我们也 可以更好地控制它 。
实际上,某些DOM方法确实需要具有最新的计算值。举例来说Element.getBoundingClientRect,或element.offsetHeight或getComputedStyle(element).height等等。所有这些需要 整个页面 已经更新,以便拳击正确做出的计算值(例如一个元素可以有一个保证金推或多或少等)。
Element.getBoundingClientRect
element.offsetHeight
getComputedStyle(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>