With nearly ubiquitous standards support among modern browsers, we're turning to CSS to handle presentational heavy lifting more than ever. The more we rely upon CSS, the larger and more complex CSS files become. These files bring with them a few maintenance and organizational challenges.
Gone are the days of creating a single CSS file and dropping in rules as needed. As we build new sites, it is necessary to spend time planning how to organize and structure CSS.
The first step in architecting our CSS is to devise a plan for organizing our files. A good organizational scheme for CSS is as important as a planned directory structure for a site. No solution is perfect for every situation, so we'll take a look at the basic choices for organization and their respective advantages and disadvantages.
The Main CSS File
You will usually start with a default CSS file that contains the rules used on every page. This file establishes defaults like fonts, anchor colors and behavior, headers, and any other properties that all pages will share. With a default file in place, let's examine high-level organizational strategies.
Method 1: Archetype-Based
The most basic strategy is to segment files based on archetype pages. For example, a site with different designs for the home page, sub pages, and portfolio pages could take advantage of an archetype system. Each page imports its own CSS file.
This method is straightforward and works well for a small number of distinct archetypes. However, it begins to fall apart if presentational elements do not fall easily into the predetermined buckets for each archetype. If there are elements that are shared by subpages and portfolio pages but not the home page, we have the following choices:
Put the shared elements in the main CSS file. While this is not the purest solution, it is appropriate in some instances. However, if you are working with a large site, the main CSS file can quickly balloon, defeating the purpose of separating the files, which is to avoid importing unnecessarily large files.
Create duplicate versions of the CSS in both the portfolio CSS file and the subpage CSS file. We clearly don't want to go this route because it would mean maintaining redundant code.
Create a new file that can be shared between the two pages. This sounds like a good solution unless we only have 10 lines of shared code. In that case we've created a whole file for just 10 lines of code. It's pure, but it becomes unwieldy if you have a large site and many pairs of pages that share a small set of unique elements.
Create a distinct CSS file to encompass all of these small cases. This might be easy, but depending on the size of your site and the number of these occurrences, you could be including a large CSS file in a situation where a page only uses a small percentage of the rules in that file. Once again, this defeats the purpose of organizing your CSS to avoid importing unnecessarily large files.
This is what I have begun to call the Overlap Dilemma. Subsets of pages overlap in their own unique way, and there isn't a clear-cut solution to cleanly organize these few small CSS rules.
Method 2: Page Element/Section-Based
This method works nicely if you use server-side includes on your site. For instance, if you use an include for your header, it would have its own corresponding CSS file. You could do the same with the footer or any other include. Then you need only include the CSS file when you reference that include from within a page. This is clean and simple, but may end up creating many small CSS files.
For example, your footer may only require 20 lines of CSS for its styling. Creating a unique file for that might be overkill. Additionally, this method could lead to including a large number of files on each page. If a page has five includes, it will need five additional CSS files.
Method 3: Tag-Based
This is straightforward and practical solution, similar to the previous one. If we have a site with 30 pages, 10 of which have forms, we could create a file that handles all of the styles for our forms and only import it on the 10 pages that use forms. Similarly, if 10 other pages use tables to display data, we could create a file to handle our table styles.
Additional Organization Tips
Along with the subjective ways of organizing files, we'll also need to consider files for varied media types such as
screen. This is more clearly defined but still a factor that we should consider when we create our file structure. When supporting different media types is a requirement, you may also want to rethink some of the rules included in your main CSS file.
Co-branding is yet another important factor that might apply to your project. If co-branding is relevant, you should determine which elements might be changed to support a different brand and separate those elements into their own unique file.
Another oft-overlooked possibility is using nested
@import statements. You can create a CSS file that only contains a series of
@import statements or use
@import to include files in one of your custom style sheets along with a series of other rules. This lets you create your main CSS files that correspond to certain sections of the site. If you find that you are importing four or five different CSS files on each page, you should definitely consider taking advantage of this tip.
Rules & Selector Organization
Now that we have our file organization in order, let's discuss how to organize everything inside of those files. Naturally, we want to navigate within the files without any problems and quickly find the selectors or rules we want to edit.
Redundancy vs. Dependency
As Dave Shea discusses in his article "Redundancy vs. Dependency," you need to be constantly aware of the cascade. You will have to decide whether you want to group selectors, which introduces dependencies, or separate the selectors, which introduces redundant code. Grouping selectors lets us to keep our code short and sweet, but it also creates a dependency that might lead to maintenance nightmares down the road. However, if we don't group those selectors and their common attributes, we increase the file size, and make it challenging to keep similar selectors consistent. You need to be aware of this trade-off so you can make the correct decision in each instance.
Group by Relationship & Context
While file organization can be subjective, it is clear that the best way to group rules and selectors is by their relationship to each other and the rest of the page. For example, if you have a container, header and footer that drive your layout, group them together.
This seems simple, but when you add in your navigation, which is contained in the header, do you group it with its parent elements or in its own new group? In this situation, consider the context of the rule within the page. Generally, your header container is related to the layout of the page, and it should be grouped with other layout elements. Your navigation, on the other hand, is one piece of the header and should probably be grouped with the other pieces of the header but not necessarily next to the header container itself.
As with most code, the key to good organization is commenting. Clearly label each section of your CSS according to what it controls. It's best to make sure that these comments stand out visually so that you can quickly identify them when scrolling through the file.
Doug Bowman has taken commenting to the next level in his article on CSS comments, "CSS Organization Tip #1: Flags." He explains how he precedes section names with an equal sign so that he can use his text editor's find feature to quickly jump to a section.
Make sure you're up to speed on the finer points of specificity, the cascade and inheritance, and use them to your advantage. Each of these can be your worst enemyor, just as easily, your best friend. When building a large site, understanding the subtleties of these pieces of the puzzle can be the difference between successfully organizing your CSS and creating a house of cards that could collapse at any moment.
We now have options for our file organization and know how to organize rules inside those files, but there's still one more level of organization. Attributes are much simpler than the other concepts presented in this article, but there are still some definite best practices for keeping your rules clean.
When it comes to attributes, if you only follow one of these guidelines, let it be this one: alphabetize. Alphabetize. Alphabetize. This doesn't help navigate your attributes, but it does help prevent you from duplicating an attribute and accidentally overriding a previous setting.
For instance, I can't count the number of times that I've specified my margin as the first attribute for a particular selector and unwittingly added a second margin attribute either before or after my original values. Naturally, the second value in the list gets used. If you don't realize the second attribute is there, you might go to adjust the first value and not see a change upon refreshing your browser. If, however, your attributes are all alphabetized, you'll see that you have specified your margins twice because both attributes would be next to each other and avoid the problem completely.
When building complex sites with numerous CSS files, you can create a large number of dependencies. When encountering a problem getting a specific attribute to apply itself to an element, the
!important option can look tempting. While this might solve the problem in the short term, it's better for the long term to determine what other attribute is causing the problem. Trace the cascade back up the tree and find out if using
!important is really the right answer.
If you are familiar with specificity, the cascade and inheritance as mentioned above, you don't need to rely upon
!important. There will be times where you need it, but you should be very aware of those instances before creating the rule. Never use
!important as a quick fix or as an afterthought because you don't know where the true source of the problem lies.
As we come to rely on CSS and the complexity of our style sheets grows accordingly, we need proper planning to avoid mistakes and ensure we write maintainable code. While there isn't always a perfect solution for every scenario, understanding how CSS works and our different options for organizing files, selectors and attributes can help us write code to stand the test of time.