I've been having a lot of trouble with bad performance on IE (all versions including IE11) in a HTML/SVG javascript-powered widget, only when the widget is hosted on a certain page.
After identifying that the main cause of the slowdown was paint / render layer redraws, and exhausting the information about these I could get out of IE Developer Tools, I resorted to trial and error turning off ancestor classes one at a time until the performance improved; then, on identifying the class, turning off style rules one at a time.
My entire problem seems to come down to a single overflow: hidden;
rule on an ancestor several divs up the tree.
The difference it makes is incredible: with overflow: hidden;
up the tree, a simple user interaction (highlighting an SVG path, generating a HTML text label, showing the label and positioning it relative to the SVG path and container) maxes out the processor, reduces the UI frame rate to zero and freezes everything dead for between 1,000 and 4,000 miliseconds per interaction. Without overflow: hidden;
on the ancestor, it completes in tens of miliseconds and the frame rate never drops below half (non-IE browsers are the same regardless of overflow: hidden;
).
Here's the profile with
overflow: hidden;
on the ancestor, profiling both on and off interactions, filtered to paint events:Here's the profile without
overflow: hidden;
on the ancestor, profiling both on and off interactions, filtered to paint events. The only change was ticking or unticking the tick box next to theoverflow: hidden;
style in the DOM inspector, and it doesn't matter in which order I do the tests:
I don't want to just override this overflow: hidden;
as a sticky plaster and say job done, not understanding how this happens and risking the problem re-occurring with other seemingly trivial CSS changes. I'd much prefer to understand why overflow: hidden;
makes such a difference and address that in a robust way which works regardless of the overflow rule applied.
Sadly I can't post a full demo but here's a summary of the relevant part of the DOM structure with comments on the layout-related styles:
<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>
What could possibly be happening here, and is there any way it can be prevented without removing / forbidding overflow: hidden;
on the ancestor element?
I've seen How to avoid the performance cost of overflow:hidden? but both questions and answers appear to be specific to HTML tables and an old Webkit bug since fixed.
They also seem specific to cases where content clipped by the overflow gets needlessly painted; a quirk of my case is that the overflow: hidden;
isn't actually clipping much (if anything) on this page (but I can't just remove it because it's part of template affecting hundreds of other pages, where it does have an effect).
Update: The plot thickens. I've managed to replicate the problem with my widget in a simpler HTML structure, and discovered that the problem only occurs if both overflow: hidden;
and border-radius
(in my case, 3px) are set on the same container. With either one but not the other, the problem disappears.