【问题标题】:Why does reflow need to be triggered for CSS transitions?为什么 CSS 过渡需要触发重排?
【发布时间】:2018-08-22 12:03:59
【问题描述】:

我正在阅读这篇文章http://semisignal.com/?p=5298,作者写道

“需要在移除不可见类之前触发重排,以便过渡按预期工作。”

我的问题是:

1) 为什么需要触发回流?

2) 我知道我们应该避免使用回流,如果这是真的,为什么作者建议使用回流来进行过渡?

3) 除了使用回流,还有其他方法可以使过渡工作吗?

谢谢。

【问题讨论】:

    标签: javascript css performance reflow


    【解决方案1】:

    (实际上是:“为什么我不能轻松地使用带有display 属性的转换”)

    简答

    CSS 过渡依赖于元素的 startingstatic 属性。当元素设置为display: none; 时,文档 (DOM) 会呈现为好像该元素不存在一样。这意味着当它设置为 display: block; 时 - 没有起始值可供它转换。

    更长的答案

    1. 需要触发重排,因为设置为display: none; 的元素尚未在文档中绘制。这可以防止转换具有起始值/初始状态。将元素设置为 display: none; 会使文档呈现为好像该元素根本不存在一样。
    2. 他建议重排,因为通常可以使用 display: none;display: block; 隐藏和显示元素 - 通常是在某个操作(选项卡或按钮单击、回调函数、超时函数等)请求元素之后。过渡是 UX 的一个巨大奖励,因此重排是允许这些过渡发生的相对简单的方法。当您在简单的网站上使用简单的转换时,它不会产生巨大的影响,因此出于一般目的您可以触发重排,即使在技术上您不应该这样做。想想这个人的例子,就像在生产站点中使用未缩小的 JavaScript 文件一样。 你可以吗?当然! 你应该吗?可能不会,但在大多数情况下,它不会产生非常明显的差异。
    3. 有不同的选项可以防止回流,或者通常比您提供的链接中的方法更容易使用。以下面的 sn-p 为例:

    A:此元素设置为height: 0;overflow: hidden;。显示时,它设置为height: auto;。我们仅将动画应用于opacity。这给了我们类似的效果,但是我们可以在没有重排的情况下转换它,因为它已经在文档中呈现并为转换提供了初始值以供使用。

    B:此元素与 A 相同,但将高度设置为定义的大小。

    A 和 B 可以很好地 淡入元素,但是因为我们立即将高度从 auto/100px 设置为 0,它们似乎在“淡出”时折叠

    C:这个元素是隐藏的,我们试图过渡孩子。您可以看到这也不起作用,需要触发回流。

    D:这个元素是隐藏的,我们动画孩子。由于动画关键帧给出了定义的开始和结束值,因此效果更好。但是请注意,黑盒会捕捉到视图中,因为它仍然附加到父级。

    E:这与 D 的工作方式类似,但我们将所有内容都从孩子身上运行,这并不能解决我们在 D 中遇到的“黑匣子”问题。

    F:这可能是两全其美的解决方案。我们将样式从父级移到子级上。我们可以从父级触发动画,我们可以控制子级的display 属性和animate 的转换。这样做的缺点是您需要使用动画关键帧而不是过渡。

    G:虽然我不知道这是否会触发函数内部的重排,因为我自己没有解析它,但您可以简单地使用 jQuery 的 .fadeToggle() 函数来完成所有这些使用单行 JavaScript,并且经常使用(或类似的 JS/jQuery fadeIn/fadeOut 方法),以至于回流的主题并不经常出现。

    示例:

    这是一个 CodePen:https://codepen.io/xhynk/pen/gerPKq

    这是一个片段:

    jQuery(document).ready(function($){
      $('button:not(#g)').click(function(){
      	$(this).next('div').toggleClass('show');
      });
    
      $('#g').click(function(){
      	$(this).next('div').stop().fadeToggle(2000);
      });
    });
    * { box-sizing: border-box; }
    
    button {
    	text-align: center;
    	width: 400px;
    }
    
    div {
    	margin-top: 20px;
    	background: #000;
    	color: #fff;
    }
    
    .a,
    .b {
    	overflow: hidden;
    	height: 0;
    	opacity: 0;
    	transition: opacity 3s;
    }
    
    .a.show {
    	height: auto;
    	opacity: 1;
    }
    .b.show {
    	height: 100px;
    	opacity: 1;
    }
    
    .c,
    .d {
    	display: none;
    }
    
    .c.show,
    .d.show {
     display: block;	
    }
    
    .c div {
    	opacity: 0;
    	transition: 3s all;
    }
    
    .c.show div {
    	opacity: 1;
    }
    
    .d div {
    	opacity: 0;
    }
    
    .d.show div {
    	animation: fade 3s;
    }
    
    @keyframes fade {
        from { opacity: 0; }
          to { opacity: 1; }
    }
    
    .e div {
    	display: none;
    }
    
    .e.show div {
    	display: block;
    	animation: fade 3s;
    }
    
    .f {
    	background: transparent;
    }
    
    .f div {
    	background: #000;
    	display: none;
    }
    
    .f.show div {
    	display: block;
    	animation: fade 3s;
    }
    
    
    .g {
    	display: none;
    }
    <button id="a">A: Box Height: Auto</button>
    <div class="a">This<br/>Has<br/>Some Strange<br/><br/>Content<br>But<br>That doesn't really<br>Matter<br/>Because shown,<br/>I'll be<br/>AUTO</div>
    <button id="b">B: Box Height: 100px</button>
    <div class="b">Content For 2</div>
    <button id="c">C: Hidden - Child Transitions (bad)</button>
    <div class="c"><div>Content<br/>For<br/>3<br/></div></div>
    <div style="clear: both;"></div>
    <button id="d">D: Hidden - Child Animates (Better)</button>
    <div class="d"><div>Content<br/>For<br/>4<br/></div></div>
    <div style="clear: both;"></div>
    <button id="e">E: Hidden - Child Hidden & Animates</button>
    <div class="e"><div>Content<br/>For<br/>5<br/></div></div>
    <button id="f">F: Child Has BG & Animates (Works)</button>
    <div class="f"><div>Content<br/>For<br/>5<br/></div></div>
    <div style="clear: both;"></div>
    <button id="g">G: This uses fadeToggle to avoid this</button>
    <div class="g">I animate with<br/>JavaScript</div>
    <footer>I'm just the footer to show the bottom of the document.</footer>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

    【讨论】:

    • 1 - “文档被绘制为好像元素不存在” document = DOM? 2- 清晰如水晶 3 - 如果我不知道高度或高度是动态的怎么办?就像一个下拉菜单。回流会是最好的解决方案吗?非常感谢,您的回答非常有帮助。
    • 1 - 是的! DOM 代表“文档对象模型”。 DOM 是从上到下创建的,就好像 display: none; 元素不存在一样。 2 - 太好了! 3 - 这真的取决于。使用高度 + 溢出确实是最直接的,特别是因为它具有语义并且易于理解正在发生的事情和原因。 height: auto 如果元素有能力也可以使用。看看这支笔的一些例子:codepen.io/xhynk/pen/gerPKq
    • 请注意,高度技巧不适用于 hiding 元素(因为它们会立即从 Y 高度变为 0。您可以查看在 JS 中使用回调函数和动画/jQuery 来规避这种情况,例如使用 fadeToggle - 但是我不知道这是否会触发回流
    • 非常感谢!!你的解释令人难以置信。我终于明白了。
    猜你喜欢
    • 2014-02-04
    • 2020-06-05
    • 2011-10-27
    • 1970-01-01
    • 2017-05-30
    • 2013-10-17
    • 1970-01-01
    • 1970-01-01
    • 2015-09-01
    相关资源
    最近更新 更多