How to structure large CSS files
Many methods exist to structure your CSS. This article tries to describe the method I use. I call it the "Tree method", since it structures the CSS like… that's right, a tree structure. I want to stress that it isn’t my invention; I just describe and give reasons for its rules.
Everyone that has built a bigger site has had to deal with the mess CSS so easily become. There are ids and classes all over the place, and to find where a certain class is defined you usually need to use some search feature in your editor. Matching the other way, from the CSS to the HTML is even harder; you don't even know what file a certain class is defined in. It’s a mess.
The Tree method tries to structure the CSS into logical blocks; blocks taken from the HTML. It also aims to be easy to understand for anyone. No secret codes or difficult ordering schemes.
- Order your selectors like the HTML
- Always use the "full path" to elements
- Indent your code cleverly
- Each declaration on its own line
- … in alphabetic order
Order your selectors like the HTML
One of the problems of mapping between the HTML and the CSS is that they usually differ in structure. The HTML is (if you’re lucky) structured like a convenient semantical tree while the CSS often is ordered by something random like fonts, colors, and positioning.
To make moving between the two worlds easier we want to make them as similar as possible. Is the HTML divided into header, content, and footer? Then make sure that's the three major parts of your CSS as well. Have you put the navigation above your header in the HTML? Then order it like that in the CSS as well! Any other structure makes moving from the HTML to the CSS much harder. You might be able to find all font manipulations in one part of the CSS, but only if you know that this particular developer uses that exact scheme. No, let’s keep it simple.
Here's a simple example where we just order the selectors:
#header { ... }
h1 { ... }
h2 { ... }
#content { ... }
p { ... }
em { ... }
strong { ... }
When grouping several styles into one definition I just put the group above both of their specific styles. #header, #content
comes before both #header and #content.
Always use the "full path" to elements
The above is very easy to get an overview of, but the experienced developer knows that very few sites are that easy. Something you often want is a way to define different styles to different parts of a page. Let’s say you want green links in the navigation, but want to keep them blue everywhere else.
For this we use sub selectors. The selector #navigation a
lets you give all links inside your navigation another look. But let’s take that further. Why not always write the full path to your elements? Why not use #navigation ul li a
instead? Doing this gives a developer looking at your code a lot of information about how the HTML and CSS belongs together.
Lets add that to the previous example:
#header { ... }
#header h1 { ... }
#header h2 { ... }
#content { ... }
#content p { ... }
#content p em { ... }
#content p strong { ... }
This does change the meaning from before. Before we selected all the level two headers; now we only select headers inside of the header division. Extending each selector with a "path" has made our CSS rules more specific, and specific means more control for you.
This also makes for fewer new ids and classes; just specify the path to an element instead of adding a class for it. Don't add a new class or id unless you really need to.
We still have the issue of "common styles"; styles that we want to apply to elements in different parts of the tree. Since they should be applied to all elements they don’t fit in the tree structure we've built. Instead we make a section in the beginning of the file (or a separate) with just "general styles". Don't add rules to this section if you only use them once in the document, you want as much of your code to be in "the tree" as possible.
Indent your code cleverly
To make the code even easier to understand I always add indentation (for those that don't know that word: it means spacing in front of blocks of text). Indenting makes the tree structure we're trying to build even clearer, you can easily find the major sections and dig down from there.
Lets add indention to you our example too:
#header { ... }
#header h1 { ... }
#header h2 { ... }
#content { ... }
#content p { ... }
#content p em { ... }
#content p strong { ... }
Don't take indentation too far. If you're styling tables and using thead in the markup, but don't change the style of it, you can skip that indentation level. Double indention just for the sake of it is just a waste of space.
Special case: Templating
We also need to deal with rules that only appear on some of our pages. Perhaps we want the home page to look somewhat different than the sub pages? We solve this by giving an id or class to the body element. Doing this lets me specify styles for just one specific page, and setting the id or class on body makes me able to change anything in the document based on that.
These page specific styles need a place in the tree too. Here I tend to break from the above scheme and put them together with the style they change. So body#page_home #header h1
is one step below #header h1
in the tree. That makes it easier to see all styles for a certain element, instead of scrolling back and fourth (like you need to do if you don't remember your general styles). Keep your templates together with the style they change instead of completely separate.
If you want bigger changes, perhaps a totally different look on some pages, there's no reason to group things according to the scheme above. Move them to a separate file instead.
Each declaration on its own line
Indentation combined with full paths makes some lines rather long. This means that putting all declarations on one line will force you to scroll horizontally, something we already avoid on our sites. The simplest way to prevent horizontal scrolling is to use one declaration per line, so that's what the tree method uses.
… in alphabetic order
Grouping of properties is another issue. I've seen grouping schemes based on all sorts of things; from splitting things into "positioning", colors, and fonts, to people adding their properties completely randomly. I've chosen to just order them alphabetically. It's one of the few methods that bring some order while still being simple enough. I've seen total beginners do this by themselves; something I believe is a good argument for it. It's intuitive.
A simple example to illustrate:
#content {
color: Blue;
font: 3.4em Arial, sans-serif;
margin: 0.5em;
}
One complaint I've heard on this method is that it splits up things that belong together. People tend to keep position: absolute
and left: 0
together, just to name one such pairing. It annoyed me at first too, but declaration blocks rarely contain more than 10 declarations, and the alphabetic order still makes them easy to find. Also, why handle position different than float and margin?
That's it! By following a few simple rules you can get a CSS-file that's easier to overview, a file that you proudly can give away to the next developer. I can praise its existence all day, but you're the judge of whether it works or not. Why not give it a try in your next project?
Update: Maurice van Creij writes in and says that he's using the same method. A good way to get started is to generate a CSS file from the HTML. He has written a javascript that does just that. Nice! Try generating a CSS file.
Update: Another part structuring your CSS is making sure you don't load too much. I wrote an article previously about combining static and dynamic CSS.
Update: This article got digged to the frontpage. There's a lot of good comments there (but as usual pretty harsh language).
Comments
By: Emil Stenström (#1)
By: Christian Tietze (#2)
First I add all usual markup. Like removing margin and padding from all elements, removing borders from images and so on. Standard indentations for lists are (re-)set here as well.
Second, there are all the layout-relevant divs (#content, #menu), ordered by appearance on screen, so header comes before content etc.
Third there ist the content markup. I may repeat #content itself, but this time it'd be for some standard styling. Ordinarily, I just put all the
#content p em
-like stuff in this second part of the code. The headings first, then paragraphs, lists etc., then some special containers like the options for blogposts which show the amount of comments, or the author or so.Your method sounds nice as well. But what's with large documents? I think it's hard to indent nested layouts very well. If the layout is centered, split and whatnot, you got two or three levels for nothing but a div at the beginning.
But the structure sounds like it's maing sense.
So, what do you suggest for the CSS markup "content"?
Do you put float, margin, width etc. above font and border?
By: Emil Stenström (#3)
I don't think large documents is such a big issue. Selectors are a small part of the code, the declarations take much more space. As for wrapper divs I don't indent them, like you say it feels like a mess, and it won't confuse anyone that I don't.
My suggestions for declarations are at the bottom :) one per line and in alphabetic order.
By: Kalle (#4)
By: Antti Kupila (#5)
Other than that i agree with everything you're saying and actually do most of my css the same way.
A new idea was to order the properties alphabetically. Could give it a try :)
By: Rowan Lewis (#6)
http://pixelcarnage.net/Projects/OneCommune/003/HTML/Styles/Global.css
http://pixelcarnage.net/Projects/OneCommune/003/HTML/Styles/Screen.css
I'm sure those two files will scare someone...
By: zcorpan (#7)
I don't bother writing the declarations alphabetically. I usually don't have a problem finding a specific declaration. Sorting them is extra work with little benefit.
By: Christian Tietze (#8)
@Emil: What exactly do you want me to explain?
By: Emil Stenström (#9)
@Antti Kupila, zcorpan: full paths is really the most important of them. With large files you need to read 100 lines up to find the top parent to a rule. If you include the full path that info is on the same line. I find that I scroll back and fourth *a lot* less when using when using them.
@Rowan: Nice! I'm just missing the full paths :)
@Christian Tietze: I just mean that what you wrote in the comment here probably is needed in a commented section in the beginning of your CSS-file. I need to try and just give one of my files to see if they can handle it without instructions. I hope so!
By: links for 2006-11-23 « mayvelous : m-a-e-e (#10)
By: Jens Wedin (#11)
http://www.nordea.se/sitemod/upload/Root/eGuidelines/stylesheets/screen_common.css
By: Emil Stenström (#12)
I'm sure yours works too though :)
By: Rob Schlüter (#13)
Property order is positioning, display, color, specific stuff (list properties, table rules), font and ends with box properties from the inside out: padding, border and margin.
I recently changed from writing every property on it's own line to combining them all on one line with the selector. I find that this gives me a better overview over the used selectors.
To overrule some CSS on specific templates you can also include a second CSS file, called the same as the template it belongs to and override styles there.
By: Emil Stenström (#14)
I prefer to keep it simple.
By: Philip Karpiak (#15)
By: John (#16)
By: John (#17)
By: Steve Streza (#18)
By: Seamus (#19)
By: Paul (#20)
Now that you've put these rules in print, I think it's time I follow them rigorously. Thanks for the post.
By: Linky na víkend 36 na depi.sk - IT & Life Weblog (#21)
By: Kyle (#22)
By: Amir’s Blog » How to structure large CSS files (Yes, you do need to structure them) (#23)
By: Ash Haque (#24)
http://www.bballcity.com/wp-content/themes/foxtrot/style.css
By: Bruce Boughton (#25)
It's generally better to be as concise as possible in selectors so that when you need to override a rule it's fairly easy to be more specific.
By: Bruce Boughton (#26)
e.g.
By: Emil Stenström (#27)
@Seamus: Good idea. You could take it even further and make little modules with CSS rules that you only include if they are needed. I wrote about that some time ago in the article Static and dynamic CSS combined.
@Paul: Good to hear. I don't want to set hard rules you never should break, always adapt the rules to the situation at hand.
@Kyle: Yes, I should have mentioned commenting as well, thanks.
@Bruce Boughton: On the contrary. I'd say a bigger problem is when other rules collide with yours and you end up with unexpected behavior. Knowing about specificity is a must though, thanks for adding it.
People that put everything on one line has their reason for it. If you want to call people idiot, please stick to digg.com :)
By: Stuart (#28)
By: Fatih Hayrio?lu’nun not defteri » 26 Kas?m WEb’den seçme haberler (#29)
By: Matt Wilcox (#30)
p { attribute : value; }
can be over-ridden by
#content p { attribute : value2; }
If you always use the 'full path' you can no longer over-ride a rule later in the document. You are ignoring the importance of the cascade and specificity by instructing people to 'always' use the full path. This is harmful to a proper understanding and use of CSS.
Other than that, there are some good ideas here. Nice one. :)
By: Emil Stenström (#31)
@Matt Wilcox: I don't find that a problem. Since you're adding rules at the most specific case (full paths), you only specify the style for that specific case. Why would you want to change that later on? The only case I see is when another "template" on your site wants to change it. That case is handled by using the suggested "body#template [full path]" trick, something that gives higher specificity and therefore works. Try it, it really works well.
By: Minimizr » Blog Archive » Minimal CSS (#32)
By: Jonathan Nicol (#33)
I'm glad to see you advocate placing each declaration on a separate line. In Jonathan Snook's recent post on the same topic he was in favor of placing all declarations on the same line, but to me, that way is a very difficult to interpret and maintain (even if it does make file sizes smaller).
Indentation is something I've recently begun to do, and I find it greatly helps with readability.
I'll try your alphabetical suggestion on my next site...
By: How to Structure CSS Files » Another Blogger (#34)
By: its about time» Blog Archive » links for 2006-11-26 (#35)
By: I Only Wish » Blog Archive » How to structure large CSS files (Yes, you do need to structure them) (#36)
By: 11/27/2006 8:03 PM - Matthew Gifford (#37)
By: Philip Withnall (#38)
By: django forums (#39)
I also prefer no space after the colon :p
ok that was anal-retentive but oh well :p
By: Emil Stenström (#40)
By: Emil Stenström (#41)
By: xocea » How to Structure Large CSS Files (#42)
By: How to structure large css files « Crossing the net as I work (#43)
By: Structuring large css files at bling bling nivas.hr blog - white and nerdy edition (#44)
By: Adam McIntyre (#45)
I was never a big fan of alphabetizing properties - I always grouped "related" items - until I gave it a chance. Now, instead of having to jump around a list of properties (width and height may "jump up" in the order if position isn't present) I can scan much more quickly.
To join the battle on specificity, I'm with Emil: as specific as possible from the get-go. This doesn't limit you from things like the cascade; rather, it lets you use the cascade to apply general properties to a large group of elements and very specific properties to very specific elements. I think specificity forces you to think about grouping and the cascade and helps reduce elements with duplicated or redundant properties, replacing them with elements gradually increasing in property specificity.
By: Emil Stenström (#46)
By: Technikwürze » Technikwürze 50 - Das Doppeljubiläum (#47)
By: Andrew Stewart (#48)
becomes:
By: Emil Stenström (#49)
By: Cum sa-ti structurezi fisierele CSS - 100%Design (#50)
By: links for 2006-11-26 // willkoca (#51)
By: ??? ??????.NET » ?????? #284 (#52)
By: » - » Estruturando o código CSS Tableless.com.br - Web Standards com Farinha e Pimenta (#53)
By: How to structure large CSS files (Yes, you do need to structure them) « Programming News (#54)
By: Johaness (#55)
The problem is if you use server side includes (e.g. PHP) and have the page header (with the opening *and* closing HEAD tags ), you will include the exact same CSS files for every page.
E.g. I include this on top of every page:
That problem can be solved with a very messy and misguided solution - conditional if statements that test for the name of each page and include accordingly.
The better way would be to use an MVC framework or plain Object Oriented PHP for a far more elegant solution.
By: lewis litanzios (#56)
one downside to splitting this info up into dedicated sections is you often find your self writing the selectors two or three times in different sections when you could, in theory, just include all properties under one selector in one place.
breaking things up has far more benefits though. for instance you can sit down and concentrate specifically on the typography for instance (although in my next project i'll be deciding upon my type before i do any layout). it's far to easy to become a whore to type once the layout is all done and dusted.
think i agree on the full path issue; i'll be implementing that in my next project. look at it this way, if you do use full paths it ties in with the alphabetical approach nicely.
not sure about the indentation thing, but nevertheless interesting. i'm one of those people that uses 'the least human readable approach', in one liners, for my css presentation. my justification is it's less scrolling down to get to what you want; once there you can obvious format it how you like when/if editing it.
i'm a big fan of CSS Formatter and Optimiser (http://tinyurl.com/2vpxfe) and use it at the end of every project to tidy things up, group selectors, shorten property values (hex colours, shorthand padding/margins etc) and generally get a nudge in the write direction for how i could make things a bit tighter in the next project.
my 3 cents :)
cheers emil!
By: Emil Stenström (#57)
@lewis litanzios: Great comment, thanks! I can see how people want to work with different sections at different times, but that's not how I work. I always start with box layout, and then complete the same rules with typography information afterwards. Works well for me.
I've actually never used a CSS Formater, but then again, I'm _very_ picky about what CSS i write, and it's almost always already optimized when I first write it.
By: lewis litanzios (#58)
'I always start with box layout, and then complete the same rules with typography information afterwards.' - so let me get this straight. you will have your universal h1, h2, h3... p typographical elements defined and then you'll target h3's and p's (and whatever) in their native divs to give them extra styling, where appropriate?
up until now i've really done my best to stick with my universal styles, but now i'm finding myself needing more than six-odd fonts per page, so am beginning to embrace semantic conventions e.g. a date font might be styled as .date{...}
i'm toying with the idea of posting a blog entry in the hope of getting some email advice;
'to use semantic id's sitewide (and have to name stuff all over the place), or use reusable classes' - what's your take?
cheers emil. big aid.
By: James O'Kelly (#59)
By: suraj (#60)
this is the way i manage my css file...& i have been succesfully used this over more than 50 projects
http://surajnaikin.blogspot.com/2008/07/how-to-manage-your-style-sheet.html
By: craig (#61)
Documentation of CSS file.doc
By: Emil Stenström (#62)
By: Damjan Mozetic (#63)
I'd rather opt for as short selectors as possible and comment my code sections appropriately to quickly find which selector represents what.
By: kit (#64)
I now group related properties on the same line, especially position-left-top; width-height; I then sort everything alphabetically. I find this makes the scanning simpler when navigating styles.
#example{
position:value; top:value; left:value;
width:value; height:value;
}
I do think the catagory ordering could be useful, especially for font styling and I'll have to see how that works out in my next project.
Also using 2 spaces for tabbing is nice too when I start getting into more complex designs
By: Richard Knop (#65)
general.css
layout.css
header.css
navigation.css
content.css
sidebar.css
footer.css
other.css
Then, I have one main stylesheet called default.css whee I import all the CSS files like this:
@import url('/css/general.css');
@import url('/css/layout.css');
@import url('/css/header.css');
@import url('/css/navigation.css');
@import url('/css/content.css');
@import url('/css/sidebar.css');
@import url('/css/footer.css');
@import url('/css/other.css');
This way the individual stylesheet files related to individual parts of the web application are smaller in size (which means I can faster find what I'm looking for and it's easier to make changes) and contain only relevant styles.
I also like to order the selectors in individual stylesheet files in the same order as they appear in the HTML markup.
By: Damien P. (#66)
first, I put all global selector like p, h1, etc.
second, I put generic classes .strong, .clear
after that, I put my selectors #header, #footer
and at the end bug fixes.