溢出怎么样:隐藏; 容器上的&border-radius导致容器内的"Paint/Render Layer"大幅减速,仅在IE上?

use*_*ca8 14 javascript css performance internet-explorer ie-developer-tools

我一直在使用HTML/SVG javascript驱动的小部件中的IE(包括IE11的所有版本)上的不良性能遇到很多麻烦,只有当小部件托管在某个页面上时.

在确定减速的主要原因是油漆/渲染层重绘之后,并且耗尽了有关这些的信息我可以从IE开发人员工具中解脱出来,我一次尝试关闭一个祖先类的试验和错误,直到性能提高为止; 然后,在识别班级时,一次关闭一个样式规则.

我的整个问题似乎归结为一个overflow: hidden;祖先的单一规则几个divs树.

它的不同之处是令人难以置信:使用overflow: hidden;树,简单的用户交互(突出显示SVG路径,生成HTML文本标签,显示标签并将其相对于SVG路径和容器定位)最大化处理器,减少UI帧速率为零,并且每次交互都会冻结所有死机,持续1,000到4,000毫秒.没有overflow: hidden;祖先,它在数十毫秒内完成,帧速率从不低于一半(非IE浏览器无论如何都是相同的overflow: hidden;).

  • 这里的轮廓用overflow: hidden;的祖先,剖析和越野互动,过滤油漆事件:

    在此输入图像描述

  • 这是不在overflow: hidden;祖先上的配置文件,分析开启和关闭交互,过滤以绘制事件.唯一的变化是overflow: hidden;在DOM检查器中样式旁边的勾选框中打勾或取消勾选,并且我执行测试的顺序无关紧要:

    在此输入图像描述

我不想仅仅把它overflow: hidden;作为一个粘性石膏覆盖并说完了工作,而不是理解这是如何发生的,并冒着问题再次发生与其他看似微不足道的CSS变化.我更倾向于理解为什么overflow: hidden;会产生这样的差异并以一种强大的方式解决这个问题,无论应用何种溢出规则.

遗憾的是,我无法发布完整的演示,但这里是DOM结构相关部分的摘要,其中包含与布局相关的样式的注释:

  <div class="responsive-grid">

  <!-- ...lots of nested divs that simply inherit styles, I can't change this aspect of the Drupal layout -->

    <div id="panel-5" class="col-12"> <!-- width: 100%; float: left -->
    <!-- this is the first element IE looks at for offsetWidth when doing the changes below -->

    <!-- ...a few more nested divs without layout-changing styles -->

      <div class="panel"> <!-- overflow: hidden; clear: both; border: 1px; -->
      <!-- this is the element where removing the overflow: hidden changes everything -->
      <!-- I'm not sure what clear:both is for here, since no siblings. Seems redundant -->

      <!-- ...a few more nested divs with no style rules, some contain <p>s <h2>s etc... -->

        <div class="container"> <!-- position: relative; -->
          <div class="sub-column col-8"> <!-- width: 66%; display: inline-block -->
            <div class="square"> <!-- width: 100%; padding-bottom: 100%; position: relative -->
              <svg viewbox="0 0 500 500" preserveAspectRatio="XMinYMin meet" ...>
              <!-- svg position: absolute; width:100%; height: 100% -->
                Many paths here

              <div class="label"> <!-- fixed width in pixels; position: absolute -->
                Some text here
              </div>
            </div>
          </div>
          <div class="sub-column col-4"> <!-- width: 33%; display: inline-block -->
             <div class="sidebar">
                Many interactive controls here

              <!-- .square, svg andd .sidebar contain the only elements that are updated -->
            </div>
          </div>
        </div>

        <!-- some more ordinary position: static text containers -->
      </div>
    </div>
  </div>
Run Code Online (Sandbox Code Playgroud)

这里可能会发生什么,有没有什么方法可以在不删除/禁止overflow: hidden;祖先元素的情况下阻止它?


我已经看过如何避免溢出的性能成本:隐藏?但问题和答案似乎都是特定于HTML表格和旧的Webkit错误.

它们似乎也特别适用于由溢出物剪切的内容被不必要地绘制的情况; 我的情况的一个怪癖是,overflow: hidden;实际上并没有在这个页面上剪切太多(如果有的话)(但我不能只删除它,因为它是影响数百个其他页面的模板的一部分,它确实有效果).


更新:情节变浓.我已经设法用更简单的HTML结构复制我的小部件的问题,并发现只有在同一容器上设置了两个overflow: hidden;和border-radius(在我的情况下,3px)时才会出现问题.任何一个而不是另一个,问题就消失了.

  • 这是一个overflow: hidden;但没有的样本border-radius.也许比上面慢一点,但差别是微不足道的:

    在此输入图像描述

  • 下面是一个样本overflow: hidden;,并border-radius从同一个简化的结构:

    在此输入图像描述

use*_*ca8 9

经过更多的测试后,我想我已经开始明白这里发生了什么.这纯粹是基于观察,所以如果有人的话,我仍然渴望获得更权威的答案.


是什么导致的?

似乎只有在所有这些都成立的情况下才会发生:

  • 浏览器是IE(任何版本)
  • 我们称之为X的祖先元素包含overflow: hidden和border-radius(或-ms-border-radius).在我的测试中,如果同一分支中的不同祖先具有这些样式,则不会发生这种情况.
  • 有许多复杂的元素,例如SVG路径或%-width div,它们位于DOM分支中,或者它们与元素X之间的元素具有position: absolute;或者position: relative;

这个问题似乎与受position: absolute;/ relative和其复杂性影响的元素数量成比例.例如,如果在响应式缩放%宽度SVG容器中存在SVG路径,其中%padding-bottom用于固定宽高比,则问题非常明显; 如果给出了这个分支,position: static但是另一个分支具有带有position: absolute;祖先的%-width div ,那么与去除其中一个overflow: hidden;或者相比,问题仍然是可观察的border-radius,但是严重程度要低得多.


但为什么?

我没有任何确定的答案,但我有一个似乎符合事实的似是而非的理论.具有讽刺意味的是,它是IE的性能优化的一个反击尝试.

我注意到offsetWidthX和路径之间的元素计算一直到路径,这对我没有意义并提示相关的问题,因为SVG容器内的路径肯定不会影响容器外的布局.

我还注意到,在研究这个问题时,其他浏览器 - 特别是旧版本的Chrome - 似乎有一个不同的问题:应该隐藏的元素正在渲染,导致速度减慢.

将这些放在一起,我认为对于这里发生的事情有一个合理的解释.如果是真的,具有讽刺意味的是,我的性能问题是由于IE的反击尝试来优化性能并避免像上面链接的现在修复的Chrome问题那样的问题.

如果这个理论是正确的,IE会发生这样的事情:

  • 它看到overflow: hidden;并得出结论,它可以通过在对它们进行重绘/重排/绘制等事件之前识别完全在元素边界之外的元素来提高性能.
  • 它看到了DOM position: absolute;并position: relative;进一步向下看,并得出结论认为这些及其子女可能完全在容器之外,可能会被忽视这样
  • 在重绘和重排等事件期间,它首先遍历所有这些元素并检查它们是否完全不在边界之内.即使没有border-radius,这仍然会发生,但在这种情况下,它是微不足道的,需要几毫秒.
  • ...但是,IE注意到border-radius并得出结论:此overflow: hidden元素的形状不是矩形,因此需要更复杂的计算来确定哪些是超出范围的
  • 据推测,它还得出结论,SVG路径需要根据它们的实际形状而不是简单的边界框坐标进行比较,因为这不再是比较平行矩形的简单问题.
  • 突然之间,用于测试在绘制/重绘/回流期间是否可以忽略元素的计算变得复杂.如果对数百个元素重复数百次,则会在每次触发事件时大幅恶化性能.

怎么解决?

如果可以,只需将overflow: hidden或移动border-radius到子元素,使它们不在同一元素上.任务完成.

然而,对我来说,我正在制作一个需要能够被放入任何地方的插件,并且无法控制其部署的页面.我不知道有什么方法可以强迫IE关掉这个行为.

我能想到的最好的方法是假设border-radius样式对于美学并非必不可少,并且overflow: hidden;可能对结构至关重要,因此,如果浏览器是IE,请查找祖先树并border-radius从任何元素中删除它和overflow: hidden;.

我的应用程序已经使用了jQuery,所以这个测试看起来像这样:

if( isAnyIE() ) {
  $container.parentsUntil("body").filter(function(){

    var $this = $(this),
      overflow = $this.css('overflow');
    return ( overflow === 'hidden' && hasBorderRadius( $this ) );

  }).addClass( 'remove-border-radius' ); 
}

function hasBorderRadius( $element ){
  function getNum( style ){
    return parseFloat( $element.css( 'border-'+style+'-radius' ) ) || 0;
  }
  var number = 0;

  number += getNum( 'top-left' );
  number += getNum( 'bottom-left' );
  number += getNum( 'top-right' );
  number += getNum( 'bottom-right' );

  $element = null;

  return !!number;
}

function isAnyIE(){
  // isIE(): use conditional comments and classes, see https://stackoverflow.com/a/18615772/568458
  // isIE10: use user agent like navigator.appVersion.indexOf("MSIE 10") !== -1;
  // isIE11: use user agent like !!navigator.userAgent.match(/Trident.*rv[ :]*11\./);

  return isIE11() || isIE10() || isIE();
}
Run Code Online (Sandbox Code Playgroud)

使用CSS像:

.remove-border-radius {
  border-radius: 0 0 0 0 !important;
  -ms-border-radius: 0 0 0 0 !important;
}
Run Code Online (Sandbox Code Playgroud)

  • 真是个传奇.微软应该雇用你. (2认同)

Con*_*Fan 8

在Joppe Kroon在2014年2月撰写的这份错误报告中,问题引起了微软的注意:

[IE 9] [IE 11] div的边框半径和溢出 而不是可见的调整大小缓慢填充div的位置 相对

当存在大量具有位置"绝对","固定"或"相对"的组合的大DIV元素,除"可见"以外的溢出和边界半径时,页面的重绘表现非常糟糕.在调整窗口大小或滚动时可以清楚地看到这一点.单个绘画事件最多可能需要1.5秒才能完成,从而导致页面无响应.

此性能问题出现在IE 11和IE 9中,但不出现在IE 10中.


微软唯一重要的回复是在2016年4月发布的.它没有提供解决方案或解决方法:

[...]我们仔细研究了您报告的问题,发现它与报告的类似问题非常相似.我们通常的决议("BY DESIGN","DUPLICATE","FIXED"等)都没有完全符合这种情况,因此我们将其标记为"不会修复",因为缺少更好的东西,但我们真正的意思是我们将以一种汇总的方式处理它,而不是在这种确切的情况下查看这个确切的事件.[...]

一切顺利,MS Edge团队

错误的状态是:关闭,因为无法修复