Welcome to “Ask a UI Guy,” an occasional new feature in which we tackle JavaScript, markup and CSS questions for an audience of server-side developers. Today’s topic: strategies for organizing your style rules into reusable components.
CSS doesn’t impose much structure on its practitioners. Individual developers must build their own structure if they wish to escape the trap of poorly organized, inefficient code.
If a project kicks off without a clear shape to its stylesheets, subsequent developers are likely to plop additional styles down wherever is convenient. It’s hard to build reusable components if every style is a one-off tied to an element id. Stylesheets with a strong skeleton and frequent signposts encourage conscientious code that’s easier to maintain.
And let’s face it: CSS tools hasn’t come as far as JavaScript ones. Sure, Firebug can help you track down why element X looks the way it does. But without a clear picture of a project’s overall CSS architecture, it’s hard to alter that element’s style properties with confidence.
Every stylesheet should tell a story
In my projects, I use a few simple tricks to encourage what I call narrative CSS. My premise is that every stylesheet should tell a story. In other words, developers should understand the structure of an application’s markup just by looking at the CSS – and understand exactly where a specific declaration can and will be used without having to grep through the entire codebase.
This tenet is based on my observations of how people make changes to existing projects: They look at the few lines of markup affected by their change, then they find the style rules that affect that markup. If the context of those style rules isn’t immediately apparent, then it’s difficult to make changes without introducing bugs or creating inefficiencies.
To accomplish this, I use the following guidelines:
- Start with a good reset.css. I recommend the Eric Meyer version.
- Use signpost-style comments to create a superstruture in the stylesheet.
- Use normal comments to create a substructure.
- Order those signposts and comments – and the rules that appear between them – from general to specific; elements to
classes toids; baselines to overrides: - Create
id-based style rules only for page-level containers: headers, footers, sidebars, main content areas. Use element- orclass-level rules for everything else. - When creating reusable utility classes that could go anywhere on the page, scope them only to a
classname unique enough to prevent common namespace collision. - When creating components that belong in a specific page-level container, scope them to the
idof that container.
All of that theory sounds, well, theoretical. How does it play out? Let’s look at the skeleton of a typical narrative stylesheet:
-
Basic HTML elements
Your first section should include baseline style rules for all common HTML elements. I sometimes mix in a few class overrides on those element-level rules so I can get fine-grained control on, for instance,
inputelements, which vary wildly depending on their type attribute./************************************************************ base element declarations ************************************************************/ body{ background: url(/sites/pfd/img/chrome/bg.png) top left repeat-x #000; color: #fff; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px; line-height: 1.5em; } h1,h2,h3,h4,h5,h6 { font-family: Helvetica, sans-serif; font-weight: bold; line-height: 1.4em; } h1 { font-size: 20px; } h2 { font-size: 16px; } h3,h4,h5,h6{ font-size: 14px; } /* links */ a { color: #08c; text-decoration: none; } a:hover { color: #444; text-decoration: underline; cursor: pointer; } abbr, acronym { text-decoration: underline; } abbr:hover, acronym:hover { cursor: help; } /* standard text tags */ b, strong { font-weight: bold; } i, em { font-style: italic; } /* forms */ input, textarea, select, .button { border: 1px solid #999; } /* you must give classes to input elements to work around limited CSS 2.1/3 support in some browsers */ input.radio { } input.checkbox { } label { display: block; font-weight: bold; } .button { background-color: #ddd; font-weight: bold; } .button:hover { cursor: pointer; } -
Reusable utility classes
Your next section should include class-based rules for reusable components that aren’t tied to a specific area of the page: pipe-delimited lists, tabs, menus, definition lists, etc.
/************************************************************ reusable utility classes ************************************************************/ /* pipe-delimited list */ ul.pipeDelimitedList { } ul.pipeDelimitedList li { } ul.pipeDelimitedList li.first-child, ul.pipeDelimitedList li:first-child { } /* tab navigation */ ul.tabGroup { } ul.tabGroup li.tab { display: none; } ul.tabGroup li.tab.activeTab { display: block; } ul.tabGroup li.tab h1 { } -
Page layout based on the
ids of major page-level containersWhen building the superstructure of your page, use
ids and scope them within each other to make the markup patterns explicit. Overkill? Maybe. But the goal here is CSS that reads like a blueprint./************************************************************ page layout ************************************************************/ #container { } #container #header { } #container #main { } #container #main #content { } #container #main #sidebar { } #container #footer { } -
Module layout, one page-level container at a time
Now we get to the heart of the stylesheet: The specific components that can appear within a given area of the page. The navigation in your header? The search box in your side navigation? The shopping cart interface? Think of each one as a reusable component that exists within the context of a page-level container.
/************************************************************ section: header ************************************************************/ /* global navigation */ #header .navigation { } #header .navigation ul { } #header .navigation .logo { } #header .navigation .logo a { } /* boilerplate */ #header .copyright { } #header .byline { } /* shopping cart */ #header .shoppingCart { } #header .shoppingCart ul { } #header .shoppingCart ul li { } #header .shoppingCart ul li.total { }/************************************************************ section: main content ************************************************************/ /* module: article */ #content .article { } #content .article h1 { } #content .article p { } /* module: product benefits */ #content ul.benefits { } #content ul.benefit li { } #content ul.benefit li a { }/************************************************************ section: sidebar ************************************************************/ #sidebar .section { } #sidebar .section dl { } #sidebar .section dl dt { } #sidebar .section dl dd { }#footer { } #footer .copyright { } #footer a { } -
Specialty code tied to float-clearing, JavaScript behaviors, or image scripts such as IEPNGFix
Finally, deal with style rules likely to contain a grocery list of selectors, such as containers that need their floats cleared or images that need to have their alpha transparency set via script in IE. Since you’ll add selectors to these grocery lists over time, it’s convenient to have easy access without searching the entire file.
/************************************************************ utilities: float-clearing, png-fixing, javascript, etc. ************************************************************/ /* float-clearing */ /* IE6 */ * html #head, * html #content, * html #content .article, * html #rail, * html #nav{ height: 1%; overflow: visible; } /* IE7 */ *+html #head, *+html #content, *+html #content .article, *+html #rail, *+html #nav{ min-height: 1%; } /* good doggies*/ #head:after, #content:after, #content .article:after, #rail:after, #nav:after{ clear: both; content: "."; display: block; height: 0; visibility: hidden; } /* IE6 hacks for image transparency */ img, #content #rail .railBlock .header, #content #rail .railBlock ul.icons li { behavior: url(/css/iepngfix.htc); } /* styles used exclusively by our jQuery plugins */ .curvyCorners { } .someAjaxPlugin { }
Does this make sense? Have a better solution to CSS organization? Let us know in the comments.

Sounds very reasonable.
I prefer, on top, to use a structured hierarchy of directories and files for CSS like
container/className1.css
container/className2/classname3.css
header/className.css
etc.
and then automcatically merge these files in the build process. This keeps the individual files in a very managable size while still keeping page load time to a minimum.
Overall good content, however I have a problem with the following statement:
“Create id-based style rules only for page-level containers: headers, footers, sidebars, main content areas. Use element- or class-level rules for everything else.”
This moves away from the point of using ID’s and Classes with CSS. For instance navigation you have a class, when it should be an ID since your only going to be using navigation once on any given page.
When you have something like a blog and you you have many “Posts” per page, then that’s when you would use a class of post or something similar.
I agree that you should use element selectors and much as possible, but when building larger sites or use a element twice in the same div for two completely different things , things can overlap and you have to create an id on that element or class if it’s used more than once on the same page.
I could go on quite a bit with this, but I think you get what I’m trying to say.
Makes sense to me. Having a system and sticking with it is always valuable. The challenge with using ID’s and classes consistently this way often comes when a stylesheet needs to coexist with Javascript. There can be a lot of advantages to tacking on a convenient ID for use as a Javascript target. Browsers still serve up an element with a unique ID much faster than one that has to be parsed out of the DOM through deep class inheritance. But you should still use the CSS cascade in parallel, to target any style rules, instead of relying on those extra ID’s for styling.
This is actually really good. I’m quite impressed, thank you!
@Stephen Korecky:
Classes are very flexible. You can use them once on a page or you can use them many times. IDs, on the other hand, can be used exactly 1 time within a given page. There may be a tiny performance hit when doing DOM script operations to find elements by class rather than ID, but with today’s browsers and frameworks, it’s negligible on anything but the largest, most complex DOMs.
Scripting aside, then, what’s the downside to using classes rather than IDs on anything but the most significant page containers? IMHO, there is none.
I have frequently regretting making something an ID – for instance, when I build a progressively enhanced Ajax interface on top of otherwise standalone pages and suddenly a page element that was unique in the non-Ajax page is repeated multiple times within the Ajax interface.
In constrast, I have never regretted using a class for a CSS hook even when that class proves to be unique to the page.
The overall point of this post was that it’s strong developer conventions, rather than the innate features of CSS itself, that lead to maintainable, narrative stylesheets. The very habit of throwing IDs on elements at the drop of a hat leads developers to think of page elements as unique rather than as reusable components that can function in a variety of environments.
@Malte
Totally agreed re: multiple files and build-time concatenation and minification. In my example “skeleton,” it would be easy to separate the styles out into element.css, utility.css, layout.css and module.css. Depending on the sheer volume of reusable modules and utilities, it may make sense to turn those files into directories with varying levels of granular files within. It all depends on the size of the project.
Thanks for bringing up this point!
@Stephen: “For instance navigation you have a class, when it should be an ID since your only going to be using navigation once on any given page.”
I gotta disagree there. How do you know that you’re only going to use navigation once? This page for instance has, by my count, four navigation areas (header, sidebar, previous/next posts, footer).
The navigation list should, IMO, use a class so that the styles common to all of the navigation lists can be declared once, and then the specific styles can be targeted either by structure (#header .navigation, #sidebar .navigation…), by additional classes (.navigation.primary, .navigation.secondary), or, finally, by ID (#primaryNavigation).
Thanks for the confirmation of what I’m doing, right down to the JS Library section (jQuery)
I would add that it’s useful to include base font sizes in, or very near, the Page Layout section. It’s common to use reduced font sizes in headers, sidebars, and footer.