Programming

CSS Optimization, digging into CSS Engine

Yesterday I asked a question on Stackoverflow as “difference between using MULTIPLE ‘id’ and ‘class’ attributes in HTML and CSS”. Though the answer was quite obvious i.e. ‘Standard says so‘ I actually asked that question to get some good reads for the weekend and Stackoverflow did not disappoint me as BoltClock gave me some real good resources to dig about CSS Parsing.

With rise of HTML5 more and more startups are looking at web as platform and making Web Applications. This further leads to construction of complex DOM Tree. Hence in such cases it is important to have CSS Optimization. This blog post emphasizes on CSS Optimization.

Before optimizing your css its important to understand how exactly browser and how CSS Engine works. When browser executes the HTML file. It first parses HTML then CSS, makes sure that it is error free followed by DOM Tree Construction where whenever a new node is created subsequent style for that element is applied from CSS [1]. So every time when a new node is created CSS Engine always go through whole CSS to find out any matching selector for that element. Due to this reason traversing the CSS rules is done from right to left instead of left to right [2]. I went too fast here. Let me explain you that with an example:

Mockup

Consider above diagram as simple webpage and the styles for above diagram is given below –

#maincontent #container1 #subcontainer-right { 
    /* Bunch of Rules */ 
}

#maincontent #container1 #subcontainer-left {
    /* Bunch of Rules */ 
}

#maincontent #container1 #subcontainer-left div { 
    /* more Bunch of Rules */ 
}

#maincontent #container1 #subcontainer-right div { 
    /* even more Bunch of Rules */ 
}

When browser starts construction of DOM Tree it will read HTML Tag then create one node then will look for CSS Rules for that element in css. It will do this for each line throughout the HTML. ie it will go through whole CSS for each HTML Tag. Offcourse there will be some algorithms implemented by browsers to avoid redundancy. Now suppose browser is constructing #subcontainer-left and wants to apply CSS Rules to #subcontainer-left what will happen if rules are traversed from Left to Right-

As I told you that for each Node Creation all CSS rules are traversed. First CSS Engine will go to #maincontent, it will check if #maincontent is same as #subcontainer-left? No. Then if #maincontent is the parent of #subcontainer-left if yes then it will reach #container1 it will check if #container is parent of #subcontainer-left then it will reach #subcontainer-right then it will realize that #subcontainer-right ≠ #subcontainer-left hence it will stop execution and will move to next line same procedure again and again. Till it applies all the rules which matches current node.

Now lets see what happens when it starts traversing from Right to Left-

It will check if #subcontainer-right is same as #subcontainer-left? No then move on go to next line. Ohh, There you are. So it will move to next selector ie #container1, is #container1 parent of #subcontainer-left? Yes. Then it will move to next selector. Is #maincontent parent of #subcontainer-left? Yes. All Confirm then apply the rules.

As you can see Right to Left saves a lot of time than Left to Right. As the it traverses whole rule only when it matches selector with current node.

So if we want to perform optimization then we have taken above procedure under consideration. Suppose I want to give some style to all those cells from ‘#subcontainer-left’, what are possible scenarios to giving CSS Rules to those Cells?

1. #maincontent #container1 #subcontainer-left * :‘*’ is known as Universal Selector it means any possible element. Using ‘*’ anywhere is as close to signing your own Death Warrant by your hand. (Watching too much crime investigation related shows these days 😉 ). Since rules traversing is done from right to left, each time CSS Engine will halt on line containing ‘*’ as key (Extreme right selector for whom you have defined the rules is known as key [3]) then it will move to its right and will perform the binary search to check if parents of that selector and current node are equal or not. This will happen everytime for each node construction.

2. #maincontent #container1 #subcontainer-left div This one is also wrong approach. Whenever div element is constructed it will halt here. Perform binary search for parents making sure that parents are same. It will still make everything expensive, as it will execute this rule for no reason when div is encountered.

3. #maincontent #container1 #subcontainer-left .cellThis approach is much bettercompare to earlier ones, but it still will be expensive. The reason would be binary search forparents. Even thought .cell is unique but still it will perform Binary Search for parents forconfirmation. This is kind of approach which you can use but trust me you can do evenmore optimization.

Best way would be to make everything unique. From Class to ids everything should be unique with no parent selectors. e.g. simply .cell {  } will make everything much faster as there will be no binary search for parents. But the problem will be of readability. Making everything unique will require proper naming conventions otherwise it will become hard to maintain the code. So make your own naming conventions according to your convenience. In above case I will prefer something like ‘.maincontent-container-cell’. You can see this name is made by simply considering the hierarchy of the elements. It will definitely make you easy to understand where exactly a node belongs. I saw this approach in one the jQuery UI plugins. However if name becomes to big you can do obfuscation later on. But having long names is always better than performing binary search.

I even got more confident about this theory when I saw Gmail’s Source Code. I’m adding snapshot of developer’s tool window.

Screen_shot_2012-03-25_at_9

You will see that there are no parent selectors. All the class names are obfuscated but having no parent selectors is what makes Gmail faster even after having too much complicated DOM Structure. You can see how deep the whole DOM is and on left the element has unique name and no parent selector. This blog may sound as premature optimization. But you will think like that because you are not aware how much intricate DOM Tree can become.

If you disagree with me or you find any flaws in the post feel free to comment. I will be happy to work on it.

References :

[1] How Browsers Work: Behind the scene of Modern Web browsers – HTML5Rocks

 

[3] Optimize browser rendering – Google Code

 

Advertisements
Standard

Express your thoughts

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s