Nested vs flat CSS: the performance question
Nested classes are one of the blessings of dynamic CSS, but they come with a lot of warnings. Generally it’s not recommended to build class structures deeper than 3–4 levels or it will impact page rendering speeds.
In other words, this:
.class-01 { background: red; }
.class-02 { background: green; }
.class-03 { background: blue; }
is supposedly rendering faster than this:
.class-01 {
background: red;
.class-02 {
background: green;.class-03 {
background: blue;
}
}
}
Which actually looks like this after processed :
.class-01 {
background: red;
}
.class-01 .class-02 {
background: green;
}
.class-01 .class-02 .class-03 {
background: blue;
}
The question is how big is the overhead when using nested classes, and how complex can it get without affecting page rendering speed?
Let’s build a test page!
For the purposes of this study I’ve generated two simple, but technically overcomplicated HTML files. Both contain 10 divs, and each has 10 further divs inside, in this fashion:
<div class="test_00">
<div class="test_01">
<div class="test_02">
<div class="test_03">
<div class="test_04">
<div class="test_05">
<div class="test_06">
<div class="test_07">
<div class="test_08">
<div class="test_09">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
The only difference between the two documents is the style sheets they use. One uses a flat stylesheet, with 100 unique classes on the same level. The other one has the classes embedded into each other in groups of 10, similarly to the arrangement of the divs themselves. Of course the latter is SCSS so it had to be processed into CSS first, and I used this CSS version for the actual testing.
You can access these files to run your own tests here:
Test results
Initial manual tests with Chrome Developer Tools’ indicated very little difference between the two. In half of the cases flat was faster, in the other half the nested won. After running ten profiling sessions, I got the following averages:
Flat CSS: 0.65 ms parsing, 4.96 ms rendering
Nested CSS: 0.89 ms parsing, 4.6 ms rendering
This looks pretty much like a draw. But let’s try something more serious.
Enter: Lighthouse
Lighthouse is a straightforward and versatile website profiling tool. It can be run as a Chrome extension, but it also works from command line or as a Node module. I used it from command line with a simple batch file which ran it 1500 times, and in each loop it rendered the flat version first and the nested version second. The metrics was saved into 3000 JSON files, which you can also find in the repo if you’d like to run your own calculations. The simple Node script used to calculate averages is also included.
Lighthouse audits a huge array of various parameters. I was looking at three of them:
First Meaningful Paint: measures when the primary content of a page is visible.
First CPU Idle: marks the first time at which the page’s main thread is quiet enough to handle input.
Time to interactive: the amount of time it takes for the page to become fully interactive.
It took about six hours to complete the test, and averaged results are the following:
Flat CSS:
First Meaningful Paint: 799.5072646533341 (800ms)
First CPU Idle: 835.319597986667 (835ms)
Time to Interactive: 845.2059313200003 (845ms)
Nested CSS:
First Meaningful Paint: 798.8996750833321 (799ms)
First CPU Idle: 834.6496750833313 (835ms)
Time to Interactive: 845.308341749998 (845ms)
This is pretty much a draw. The difference is around 0.01ms or even less on average which doesn’t warrant any kind of concerns. Even by blatantly disregarding best practice and racking classes into a heap there is no significant difference in CSS performance.
Feel free running your own test on the data published in my repo. Feedback is appreciated.