emrys golden
emrys golden

Reputation: 57

display: none in a for loop and its affect on reflow

I was reading through some code today and came across this for loop:

for (i=0; i<100; i++){
    document.getElementById(elem + i).style.display="none";
}

I've only just begun to learn about browser reflow; However, my current understanding is that this loop is causing a reflow for each of the 100 elements it is setting to display none.

What are the effects of this loop on the DOM? Is this really as horrible as I think it is?

This code is used while rending a new page.

Upvotes: 1

Views: 1649

Answers (2)

A. Vidor
A. Vidor

Reputation: 2550

The Chrome Developer Tools timeline is a great way to test these kinds of questions, especially since "as horrible as I think it is" is fairly subjective.

I ran a test of the code you posted in this fiddle. Call this Test 1.

  • Note that I used 1000 elements, instead of 100, for the test.

For control, I hid the elements efficiently by setting a wrapper element to display:'none' in an animation frame, using the code in this fiddle. Call this Test 2.

  • In Test 1, rendering took 17.6 milliseconds.
  • In Test 2, rendering took 1.5 milliseconds.

So the empirical answer is yes, the tested code requires more than 10x the computation time to reflow the page layout, versus an alternative (ideal) method. Without knowing more about the code from which it is extracted, it is hard to say whether the method used is appropriate or necessary.

For example, if the elements to be hidden aren't neatly wrapped in their own wrapper <div>, optimization is difficult. A strategy that avoids the for loop would be to assign the elements a "hideable" class, and set up a CSS rule like wrapper.hideChildren > .hideable { display:none; }. Then, when we assign class "hideChildren" to the wrapper, the marked elements are hidden. Using this strategy, I was only able to get rendering time down to 15ms, or 10ms when the wrapper was detached from the DOM before the manipulation, and re-attached afterwards. In other words, the for loop may not incur that much of a performance penalty. Bear in mind that 17ms is roughly 1 frame of animation at 60 frames-per-second.

If you examine the screenshots at the end of this post, you will notice that even in Test 1, all "scripting" (the execution of the for-loop) happens in advance of all "rending" (re-flow). So if your question is, "will the browser alternate scripting and rendering at each iteration of the loop", then the answer is no, at least in Chrome 50.

As for fridge_light's link in the comments, the linked documentation never states that setting display:none won't trigger a reflow; it just includes a chart from a video that it links to, without a legend. Setting display:none will change the layout: the height of the document may change, elements flowed beneath the hidden element will be shifted closer to the top of the document, elements inline with the hidden element will shift in-line, floated elements will change position around it, etc. So there is necessarily some computation done by the browser.

Your question is a little confused: the DOM is not necessarily related to page re-flow. Re-sizing the browser window, for example, may trigger a re-flow without affecting the DOM at all! Setting display to none removes an element from the page layout/flow, but leaves it in the DOM.

Test 1 Test 1

Test 2 Test 3

Upvotes: 5

For the code you show, No, it's not

Upvotes: 0

Related Questions