Javascript 如何溢出:隐藏&;集装箱上的边界半径会导致大量减速;“油漆/渲染层”;容器内,仅在IE上?
在一个HTML/SVG javascript驱动的小部件中,IE(包括IE11在内的所有版本)的性能很差,只有当小部件托管在某个页面上时,我才会遇到很多问题 在确定速度减慢的主要原因是绘制/渲染层的重画之后,我采用了反复尝试的方法,一次关闭一个祖先类,直到性能得到改善;然后,在识别类时,一次关闭一个样式规则 我的整个问题似乎归结为一个Javascript 如何溢出:隐藏&;集装箱上的边界半径会导致大量减速;“油漆/渲染层”;容器内,仅在IE上?,javascript,css,performance,internet-explorer,ie-developer-tools,Javascript,Css,Performance,Internet Explorer,Ie Developer Tools,在一个HTML/SVG javascript驱动的小部件中,IE(包括IE11在内的所有版本)的性能很差,只有当小部件托管在某个页面上时,我才会遇到很多问题 在确定速度减慢的主要原因是绘制/渲染层的重画之后,我采用了反复尝试的方法,一次关闭一个祖先类,直到性能得到改善;然后,在识别类时,一次关闭一个样式规则 我的整个问题似乎归结为一个溢出:隐藏对一个祖先的规则树上的几个分区 它所带来的差异是难以置信的:带有溢出:隐藏在树上,一个简单的用户交互(突出显示SVG路径,生成HTML文本标签,显示标签并
溢出:隐藏代码>对一个祖先的规则树上的几个分区
它所带来的差异是难以置信的:带有溢出:隐藏代码>在树上,一个简单的用户交互(突出显示SVG路径,生成HTML文本标签,显示标签并将其相对于SVG路径和容器进行定位)可以最大限度地提高处理器的性能,将UI帧速率降低到零,并在每次交互中将所有内容冻结1000到4000毫秒。无溢出:隐藏在祖先上,它在数十毫秒内完成,帧速率从不低于一半(非IE浏览器是相同的,无论溢出:隐藏;
)
- 下面是带有溢出的配置文件:隐藏祖先上的代码>,分析打开和关闭的交互,过滤以绘制事件:
- 下面是没有溢出的配置文件:隐藏祖先上的code>,,分析开和关交互,过滤以绘制事件。唯一的变化是勾选或取消勾选
溢出:隐藏旁边的勾选框样式,并且测试的顺序无关紧要:
我不想只覆盖这个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>
这里有很多路
这里有一些文字
这里有很多交互控件
这里可能发生的事情,以及在不删除/禁止overflow:hidden的情况下,是否有任何方法可以防止它发生祖先元素上的代码>
我已经看到了,但问题和答案似乎都是针对HTML表的,而且一个旧的Webkit bug已经修复
它们似乎也特别适用于被溢出剪裁的内容被不必要地绘制的情况;我的案例的一个怪癖是溢出:隐藏
实际上并没有在这个页面上裁剪太多(如果有的话)(但我不能仅仅删除它,因为它是影响数百个其他页面的模板的一部分,在其他页面上它确实有效果)
更新:绘图变厚。我设法用一个更简单的HTML结构复制了我的小部件的问题,并发现只有当twareoverflow:hidden
和边界半径
(在我的例子中是3px)设置在同一个容器上。不管是哪一个,问题都消失了
- 下面是一个带有
overflow:hidden的示例代码>但不是边界半径
。可能比上面稍微慢一点,但差别很小:
- 下面是一个带有
overflow:hidden的示例代码>和边界半径
来自同一简化结构:
经过更多的测试,我想我开始了解这里发生了什么。不过,这纯粹是基于观察,所以如果有人有更权威的答案,我仍然渴望得到一个更权威的答案
是什么原因造成的?
这似乎只有在所有这些都是事实的情况下才会发生:
- 浏览器是IE(任何版本)
- 我们将称为X的祖先元素同时包含
溢出:隐藏和边界半径
(或-ms边界半径
)。在我的测试中,如果同一分支中的不同祖先具有这些样式,则不会发生这种情况
- 在DOM分支中有许多复杂的元素,例如SVG路径或%-width div,它们或它们与元素X之间的元素具有
位置:绝对代码>或<代码>位置:相对代码>
这个问题似乎与受位置影响的元素数量成正比:绝对代码>/相对的
及其复杂性。例如,在响应缩放%-宽度SVG容器中存在SVG路径且底部填充%用于固定纵横比的情况下,问题非常明显;如果此分支给定了位置:静态
,但另一个分支具有带位置:绝对的%-width divs代码>祖先,那么与删除溢出:隐藏中的一个相比,问题仍然可以观察到代码>或边界半径
,但严重程度要轻得多
但是为什么呢?
我没有任何明确的答案,但我有一个似乎符合事实的似是而非的理论。具有讽刺意味的是,这将是IE在性能优化方面的一次适得其反的尝试
我注意到,offsetWidth
对X和路径之间的元素的计算一直到路径,这就是bec
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();
}
.remove-border-radius {
border-radius: 0 0 0 0 !important;
-ms-border-radius: 0 0 0 0 !important;
}