CSS Best Practices
As mentioned before in earlier posts, I’m involved in a Web application development project. Recently I had to do some testing on the Web application (although it’s barely beta ready, but that’s a different story). During the testing process, I’ve got to see for myself the implications of not incorporating scalability designs early on into the code.
This post will take a simplistic approach to look at why load times can be improved by consolidating CSS files. At the same time, I will also take a look at naming CSS selectors as the approach to consolidating CSS. By taking a consistent approach to naming CSS selectors and organising the selectors in a structured manner in CSS files, we can minimise the number of CSS files.
The Why
One aspect has to do with the number of CSS files an application loads. (The same principle applies to JavaScript. But I shall discuss that in another post.) The number of CSS files in a webpage affects how many HTTP requests are required before the page is considered fully loaded.
Let’s begin by thinking ourselves as the Web browser. Suppose we first visit this page and it has 10 CSS files. After fetching the HTML of the page, we have to go on to fetch the CSS files. Because there are 10 files, we issue 10 HTTP requests to fetch the CSS. On the other hand, if there were only 1 CSS file, we’d just fetch 1 file. Consider the overheads in establishing 10 HTTP connections compared to one – multiply that by a thousand times (for 1000 users) and you’ll realise the significant amount of savings you can achieve by consolidating 10 files into one. (Note that I’m oversimplifying here by saying that there 10 connections for 10 CSS files since more than one file may be transmitted using persistent connections. But for the sake of this post, it’s okay to assume that.)
In case you think I’m exaggerating the problem (as I was wont to do before I embarked on the testing exercise), assume that each HTTP request takes 20ms; 9 requests take 180ms. Multiply 180ms by 1000 (users) and you get 180 seconds! Assume that your Web server is able to process 30 requests at a time, you still get about 6 seconds of redundant loading time. (Before you throw eggs at me for this simplistic calculation, know that this is for illustration purposes and not an accurate estimation exercise.) That’s 6 seconds of unnecessary waiting time.
“But isn’t that the same as loading one big file?” you ask. Well, the above calculation takes into consideration only the overheads not the downloading of the actual file. By combining 10 CSS files into one, it is reasonable to say that the total file size should be the same right? So no matter if you are downloading 10 individual CSS files or one combined large file, the total transfer size is the same. Yet, the overheads for one file is so much lesser than for 10 files. Furthermore, with modern content delivery networks (CDNs) and browser caching facilities, a single file is easily cached in multiple places for optimum delivery to the end user.
The How
So now that we know the benefits of consolidating multiple CSS files into one, let’s see how we can do it. Some of you reading now might be wondering “Isn’t combining multiple files into a process of copy and paste?”
Well, in a way, yes. But when you have a few hundred selectors in your CSS, you NEED to manage. There are two parts to it – first is the organization of the selectors in the CSS file, next is the naming of the selectors.
For the file organization, I use the tips from this post (http://www.dezinerfolio.com/2009/02/20/css-standards-best-practices), specifically the part on “Anchors”. In short, group the selectors according to the function they perform and name those sections with two underscores as the prefix. For example, for selectors that style the menu, they can be placed under the title “__menu”.
Previously when I read the post, I wondered why bother organising the selectors in a file when you could just place them in multiple files. After going through “The Why” above, I saw the wisdom behind that decision. The linked post has a detailed description of how the selectors may be organised so I shall not delve into that. You need to be able to distinguish the selectors that go into structuring the layout and those that are for decoration (i.e. the helpers).
For my application, I deviated a bit from that – there are certain styles that are only loaded in certain pages. For these styles, I placed them into a separate file, contrary to what I described early on. Why? The reason is to improve the loading of the first page. By placing only the common styles that are found on every page in the first file, the file gets loaded faster. Other styles placed in the second file get loaded when they are required on the specific page. Since the first CSS file is already loaded in the first page, the browser would have cached it, therefore the page will only need to load the second CSS file – one HTTP request.
For the naming of the selectors, I shall describe it in the context of my application. As any developer knows, a CSS selector may also be used by Javascript to target elements. Managing the multitude of selectors and negotiating the use of the selectors between styling (by CSS) and functional (Javascript). I tackle this problem by adopting a naming policy for all selectors.
Guideline 1: Separate CSS selectors by dashes/hyphens (-)
Aside from the possible failure of older browsers in recognising the selector I use the dash to separate the different names. Underscores can possibly be used to indicate a space.
Guideline 2: Prefix selectors according to the function/module
I prefix selectors that are meant for Javascript consumption with two letter abbreviations such as ac- for auto-complete, ax- for AJAX elements, wg- for widgets, etc.
As I have modules in my application, I also prefix elements with the name of the module if the element belongs specifically to a module. This rule is less clear-cut; it depends on the element and the purpose. It really boils down to your personal preference and experience.
Guideline 3: Don’t style functional selectors
Functional selectors are for Javascript. Rarely do they need to be styled, unless they are for widgets. This follows the presentation and content separation paradigm between HTML and CSS, except that this guideline separates function from presentation.
However, if the Javascript is for widgets, usually they need to be styled, in which case, function cannot be separated from presentation.
Guideline 4: Always place design selectors after functional selectors
This is a follow-up to guideline 3. Since design selectors always specify design, the design usually take precedence over any inherent design in functional selectors (for example, widgets) so they should be placed after functional selectors.
Just to be clear, this section describes the placing of selectors in the class attribute of elements.
Guideline 5: Style the same elements with different context where possible
If an element is to be styled differently for different pages, elements, etc., they should be styled with accordingly. For example, the HTML is:
<div class="qn-worksheetcreation">
<form class="fm-worksheetcreation">
</form>
</div>
the CSS should be:
.qn-worksheetcreation .fm-worksheetcreation {
...
}
These are some of the basic principles I follow for my web project. I look forward to any suggestions that you might have in the comments!