Jump to main navigation, main content

Archived entry | Matt Wilcox .net

Organising CSS, revisited

I like my websites to be well organised, from the directory structure and general naming conventions, right down to consistent code indentation. I borrowed a lot of this attitude from coding PHP and reading up on software engineering - it makes sense to create a sensible standard in how to write code and files. Doing so helps keep things organised and easy to understand - Even to someone who’s never seen the code before.

Over time I’ve gone through a number of different ways of organising my CSS, and I’ve never been totally happy with any of them. Since the last time I wrote on the subject I have refined my methodology in a number of ways, and I’d like to share them with you.

Organising CSS files

I now use a method consisting of four files:


This is the main one. It contains CSS for the entire site, and is written as though the user agent understood Web Standards and CSS2 / CSS3 perfectly. It contains no hacks and no invalid rules. As the name implies, it contains styles for on-screen display.

I target individual pages for styling by ensuring the <body> tag has a unique class on it, for example:

  1. <body id="mattwilcox-net” class="about”>

I can then target that specific page in my CSS as follows:

  1. .about * { property : value; }

All my XHTML pages contain a conditional comment which forces IE and only IE to load screen_ie.css. This file is where I help tired old Internet Explorer out. I over-ride any rules from screen.css that IE isn’t understanding or applying correctly, and supply whatever values or selectors IE needs to achieve a similar look to what any modern browser would give. If it’s not possible to achieve the same results as a modern browser then I patch IE up so at least it doesn’t look broken. The CSS in this file is also free of hacks, and validates correctly.


The idea of this file is to contain any non-standard and proprietary CSS that specific browsers can use, in order to enhance the look of the site on those browsers. In practice I only ever target Mozilla based browsers, and only to give input fields rounded corners, should the design call for it. I could optionally choose to put some of IE’s proprietary CSS rules and filters in here if I wanted to.
Because this file contains non-standard rules or selectors, it’s the only one I allow to not validate.


This file is only called when someone goes to print the page, and works in the same manner as screen.css, but for print media. As my print styles are intentionally basic (to suit the media) there usually isn’t a need to create a print_ie.css file.

This ‘four file’ method is extensible, so if I want to create a stylesheet for use with a projector display I could just create a projection.css file, and if needed projection_ie.css, importing both in the same manner as I would screen.css and screen_ie.css.

Organising rules

I have found that the best way to organise my rules is to group them by selector, rather than by context, and use flags to mark selector sets.
Attributes within a rule effect any element matching the last selector in that rule (and any prior selectors, but the end one is ‘the daddy’ and has the final say on exactly which element gets styled) - so it makes sense to group rules by the final element selector. Such grouping makes it easy and intuitive to find any rule you want. For example, if you are looking for a dodgy style that’s effecting a paragraph in your header, you know to look at the /* =p */ section. The alternative is to try and find where in the CSS you grouped all the rules that effected your header area, and then trawl through them all looking for a rule ending with a ‘p’.

As mentioned, I use ‘flags’ to denote where a selector set starts, in the form of a comment. By using a /* =selector */ flag it’s easy to jump to wherever I need to be in a document using my editors ‘find’ functionality. Additionally these flags keep the file organisation clean and clear.
I also group rules under a flag based on the page they apply to. A snapshot of some CSS might look as follows:

  1. /* =ul */
  2. .about #content_main ul { margin-bottom : 1em; }
  3. .about #content_supp ul { margin-bottom : .5em; }
  5. .home #intro ul { font-size : .75em; }
  6. .home #content_supp ul { fcolor : #fea; }
  8. /* =li */
  9. .about #content_main li { font-weight : bold; }

Another advantage to grouping rules by selector is that it can often make for more optimized CSS as well as more organised CSS. After all, it’s likely that you will want to style identical elements similarly, which means you can often group selectors into a single rule, as follows:

  1. /* =p */
  2. .about #intro p,
  3. .contact form p,
  4. .home .post p { attribute : value; }

Organising CSS attributes

Creating a new line after each attribute makes a file that is far too long for my liking, requiring huge amounts of vertical scrolling, so I stopped laying out my attributes like that a long time ago. After working with Andy Clarke for quite a while, I adopted his method of laying out rules & attributes: keeping each rule and its attributes on a single line. The advantage of this approach is a very short file, requiring little vertical scrolling, and making the task of finding a selector very easy and fast. Unfortunately it also means you need to scroll horizontally a lot of the time, because the lines get very long, and finding a particular attribute within a rule can be a bit of a pain.

In an effort to find some middle ground I now use a hybrid method, which relies on good indentation for maintaining easy vertical ’scanning’ when looking for a rule. I split the attributes up into three lines, below the selector. This means the selector is on its own line, and the attributes fall below the selector. The first line holds any attributes which will affect the position of the element (the ‘positioning’ line), the second holds attributes that affect the size of the element (the ‘box’ line), and the third holds any remaining attributes, mostly governing appearance and content (the ‘content’ line).
An example of this type of layout looks like this:

  1. /* =p */
  2. .home #content_main p.intro {
  3. position : absolute; top : 0; left : 0;
  4. margin : 0; padding : 1em; border : 1px solid #fff;
  5. font-size : 1.6em; z-index : 2; }
  6. .home #content_sub p {
  7. margin : 0; padding : 1em; border-width : 0;
  8. font-size : 1.2em; color : red; }

If the rule doesn’t require all three lines I just collapse them.


The methods I use to organise my CSS are ones that I use daily, and they work for me better than any other methods I have tried. They may not work so well for you, and you may not see an advantage in the way I do things compared to your own methods, but I’ve put this out there, hopefully to help people, and possibly to learn myself - if anyone has any better methods please let me know. smiley icon: happy

Bringing it all together

Here is an example of how some CSS would look when all of the above ideas are brought together. Note how the flags mark sections clearly, and how the two levels of indentation make it intuitive and easy to find where rules begin and end.

  1. /* =ul */
  2. #content_main ul {
  3. margin : 0 0 1em 2em;
  4. list-style-position : outside; }
  6. .home #content_main ul {
  7. margin : 0; }
  8. .home #content_sub ul {
  9. margin : 1em 0; padding-bottom : 1em; border-bottom : 1px solid red;
  10. color : #fff; font-weight : bold; }
  12. /* =li */
  13. #content_main li {
  14. position : relative;
  15. color : #f33; }


If you take a look at the XHTML and CSS on this site, you’ll notice that I’m not actually using the above methods. I’m not being hypocritical - I just haven’t gotten around to shifting my old code to the newer format yet. smiley icon: laugh


skip to comment form
  1. Matthew J. Ward posted 20hrs, 12min, 23sec after the entry and said:

    Nice repository you've started there Jimski.

    Makes total sense even to a web noob like me
    I guess everyone has there own way of doing things, but it looks logical to me.

  2. Rhyno posted 11 days, 18hrs, 19mins after the entry and said:

    Hi Matt,

    Great idea on organizing rules by selector! Too many times I've fumbled around trying to figure out why a certain element (especially ULs and LIs) are behaving wonky. Keeping them nestled together is an easy way to view behaviors at-a-glance.

    However, I tend to disagree with loading all attributes on one line. I, and I presume most people, prefer vertical to horizontal scrolling. Whenever you have to go horizontal, you usually have to go BACK the other way, and THEN up/down to move on in the file. Not good.

    Instead, how about using a nice editor like Notepad++:
    which auto-recognizes just about every type of file, and acts accordingly. In the case of CSS, it lets you rollup selectors using twirlies. Too much vertical for you? Just collapse the ones you don't need. Great proggie.

  3. Matt Wilcox posted 11 days, 20hrs, 24mins after the entry and said:


    Perhaps I wasn't clear - I don't like CSS rules all on one line either, for exactly the reasons you describe - that's why I've started splitting them onto three, as descibed in the article.

    I've not tried Notepad++, but my editor of choice does support folding, though I tend not to use that particular feature. Cheers for the heads up - I shall take a look at Notepad++ and see if it's got what it takes to replace Jedit (which is my editor of choice).

  4. MWF posted 21 days, 13hrs, 55mins after the entry and said:

    What a totally non-anarchistic approach. Personally I write and organise CSS differently every time. What can be more fun than going to edit and old site and finding the headings are all defined in about three different places in a format you can't even remember writing them in.

    I'm still at the, what I like to call, "Crazy Sandwich" stage of CSS use.

  5. bart posted 88 days, 17hrs, 3mins after the entry and said:

    This is much different than any other organizational method I've seen so far. It seems like it make sense and may make the cascade of styles and specificity issues a little easier to nail down (without having to rely on DOM Inspector). Although, how do you deal with inheritance? For example, if you set font properties on the body and then on an element…I guess you just have to be careful with these things at all times. Thanks for sharing your method.

  6. Matt Wilcox posted 88 days, 17hrs, 18mins after the entry and said:

    Handeling specificity can be hard, but I always try and use the least specific rule I can, which helps later if I need to over-ride any style. e.g.,

    .about #content_main p { attribute : value; }

    rather than

    body.about div#content_main p { attribute : value }

    Managing the cascade is the most tricky bit of CSS, and there's no easy way of making the cascade obvious in the CSS itself (at least, not that I've found). That's where FireBug or the DOM Inspector come into their own - they're just what's needed to figure out what CSS is effecting what elements.

  7. david hayes posted 2 years, 257 days, 2hrs after the entry and said:

    I'm currently going a little crazy thinking about how I do CSS and how I can do it better.

    I find the idea of organizing by selector really interesting, but I can't quite wrap my head around it. To me, geography still matters more than type.

    Beyond that one though, I really like some of your ideas (especially the three lines thing) and am going to be think about them as I choose my own best way.

    Thanks very much for sharing.

  8. Ryan posted 4 years, 139 days, 21hrs after the entry and said:

    I've just tried your method on my latest project and it really has made a difference to how efficiently I can source the correct style. I feel that bit more organised now smiley icon: wink I appreciate you taking your time to share this. Thank you

From the archives

Other enteries filed under:

Web Development

Site information

Built with valid XHTML and CSS, designed with web standards and accessibility in mind. Best viewed in a modern browser [Firefox, Safari, Opera]

This domain and all content is a copy of my old website, for historical purposes only.