views:

1245

answers:

7

I have been heavily relying on CSS for a website that I am working on (currently, everything is done as property values within each tag on the website and I'm trying to get away from that to make updates significantly easier).

The problem I am running into, is I'm starting to get a bit of "CSS explosion" going on. It is becoming difficult for me to decide how to best organize and abstract data within the CSS file. For example:

I am using a large number of div tags within the website (previously it was completely tables based). So I'm starting to get a lot of CSS that looks like this...

div.title
{
  background-color: Blue;
  color: White;
  text-align: center;
}

div.footer
{
  /* Stuff Here */
}

div.body
{
  /* Stuff Here */
}

etc. It's not too bad yet, but since I am learning here, I was wondering if recommendations could be made on how best to organize the various parts of a CSS file. What I don't want to get to is where I have a separate CSS attribute for every single thing on my website (which I have seen happen), and I always want the CSS file to be fairly intuitive.

(P.S. I do realize this is a very generic, high-level question. My ultimate goal is to make it easy to use the CSS files and demonstrate their power to increase the speed of web development so other individuals that may work on this site in the future will also get into the practice of using them rather than hard-coding values everywhere.)

+1  A: 

A lot of times I will see individuals break the file out into sections, with a heading comment between sections.

Something like

/* Headings and General Text */

.... stuff here for H1, etc..

/* Main page layout */

.... stuff here for layout page setup etc.

It works pretty well and can make it easy to go back later and find what you are working on.

Mitchel Sellers
This says nothing about the asker's concern about having "a separate CSS attribute for every single thing".
gWiz
+79  A: 

This is a very good question. Everywhere I look, CSS files tend to get out of control after a while - especially, but not only, when working in a team.

The following are the rules I am myself trying to adhere to (not that I always fully manage to.)

  • Refactor early, refactor often. Frequently clean up CSS files, fuse together multiple definitions of the same class. Remove obsolete definitions immediately.

  • When adding CSS during fixing bugs, leave a comment as to what the change does ("This is to make sure the box is left aligned in IE < 7")

  • Avoid redundancies, e.g. defining the same thing in .classname and .classname:hover.

  • Use comments /** Head **/ to build a clear structure.

  • Use a prettifier tool that helps maintain a constant style. I use Polystyle, with which I'm quite happy (costs $15 but is money well spent). I'm sure there are free ones around as well (Update: like for example Code Beautifier based on CSS Tidy, an open-source tool I've not used myself yet but looks very interesting.)

  • Build sensible classes. See below for a few notes on this.

  • Use semantics, avoid DIV soup - use <ul>s for menus, for example.

  • Define everything on as low a level as possible (e.g. a default font family, colour and size in the body) and use inherit where possible

  • If you have very complex CSS, maybe a CSS pre-compiler helps. I'm planning to look into xCSS for the very same reason soon. There are several others around.

  • If working in a team, highlight the necessity of quality and standards for CSS files as well. Everybody's big on coding standards in their programming language(s), but there is little awareness that this is necessary for CSS too.

  • If working in a team, do consider using Version Control. It makes things that much easier to track, and editing conflicts that much easier to solve. It's really worth it, even if you're "just" into HTML and CSS.

  • Do not work with !important. Not only because IE =< 7 can't deal with it. In a complex structure, the use of !important is often tempting to change a behaviour whose source can't be found, put it's poison for long-term maintenance.

Building sensible classes

This is how I like to build sensible classes.

I apply global settings first:

body { font-family: .... font-size ... color ... }
a { text-decoration: none; }

Then, I identify the main sections of the page's layout - e.g. the top area, the menu, the content, and the footer. If I wrote good markup, these areas will be identical with the HTML structure.

Then, I start building CSS classes, specifying as much ancestry as possible and sensible, and grouping related classes as closely as possible.

div.content ul.table_of_contents 
div.content ul.table_of_contents li 
div.content ul.table_of_contents li h1
div.content ul.table_of_contents li h2
div.content ul.table_of_contents li span.pagenumber

Think of the whole CSS structure as a tree with increasingly specific definitions the further away from the root you are. You want to keep the number of classes as low as possible, and you want to repeat yourself as seldom as possible.

For example, let's say you have three levels of navigational menus. These three menus look different, but they also share certain characteristics. For example, they are all <ul>, they all have the same font size, and the items are all next to each other (as opposed to the default rendering of an ul). Also, none of the menus has any bullet points (list-style-type).

First, define the common characteristics into a class named menu:

div.navi ul.menu { display: ...; list-style-type: none; list-style-image: none; }
div.navi ul.menu li { float: left }

then, define the specific characteristics of each of the three menus. Level 1 is 40 pixels tall; levels 2 and 3 20 pixels.

Note: you could also use multiple classes for this but Internet Explorer 6 has problems with multiple classes, so this example uses ids.

div.navi ul.menu#level1 { height: 40px; }
div.navi ul.menu#level2 { height: 20px; }
div.navi ul.menu#level3 { height: 16px; }

The markup for the menu will look like this:

<ul id="level1" class="menu"><li> ...... </li></ul>
<ul id="level2" class="menu"><li> ...... </li></ul>
<ul id="level3" class="menu"><li> ...... </li></ul>

If you have semantically similar elements on the page - like these three menus - try to work out the commonalities first and put them into a class; then, work out the specific properties and apply them to classes or, if you have to support Internet Explorer 6, ID's.

Miscellaneous HTML tips

If you add these semantics into your HTML output, designers can later customize the look of web sites and/or apps using pure CSS, which is a great advantage and time-saver.

  • If possible, give every page's body a unique class: <body class='contactpage'> this makes it very easy to add page-specific tweaks to the style sheet:

    body.contactpage div.container ul.mainmenu li { color: green }
    
  • When building menus automatically, add as much CSS context as possible to allow extensive styling later. For example:

    <ul class="mainmenu">
     <li class="item_first item_active item_1"> First item </li> 
     <li class="item_2"> Second item </li> 
     <li class="item_3"> Third item </li> 
     <li class="item_last item_4"> Fourth item </li> 
    </ul>
    

    This way, every menu item can be accessed for styling according to its semantic context: Whether it's the first or last item in the list; Whether it's the currently active item; and by number.

Note that this assigning of multiple classes as outlined in the example above does not work properly in IE6. There is a workaround to make IE6 able to deal with multiple classes; I haven't tried it yet but looks very promising, coming from Dean Edwards. Until then, you will have to set the class that is most important to you (item number, active or first/last) or resort to using IDs. (booo IE6!)

Pekka
+1, I would just like to see the "build sensible classes" point a little more developed.
Alix Axel
Thank you for these suggestions. Very good list and brought up things I hadn't even considered.
JasCav
@Alix Axel, very good point. I'll see whether I get around to elaborating some more on that later. @Jason you're welcome - actually it's a good thing for myself to actually put this into words.
Pekka
@Alix Axel and @all, I tried to elaborate a bit on what I believe is sensible building of classes. Feedback very welcome, also on whether it is understandable at all. It's quite tough to put into words. Also, is it too much?
Pekka
One day (when browsers that don’t support `:first-child` and `:last-child` are a distant memory in our log files), we can get rid of `item-first` and `item-last`. Not yet though. (Hello, IE 6.) I sometimes call these `first-child` and `last-child`, just to make it clearer what they’re filling in for.
Paul D. Waite
@Paul cheers for mentioning the proper CSS syntax and IE6, because IE6 has trouble with multiple classes assigned to an element, so my example won't work out of the box. Added caveats.
Pekka
Oh yeah — sometimes I pop in a multiple class selector because it’ll work in IE 6 with the way the code is now, then later I’ll change something and suddenly IE 6 is shot to hell because the assumption that made the multiple class selector work isn’t there any more. It’s such a useful selector. ie7-js works great whenever I’ve used it (I haven’t used it extensively).
Paul D. Waite
@Pekka: This is great, I would upvote you again if I could.
Alix Axel
@Alix Axel thanks!! @Paul good to know it works well, it's not always the case with IE6 band-aids.
Pekka
@Pekka @all - Excellent answer and very well thought out. Thank you for taking the time to give all the input!
JasCav
a little bit off topic. you might want to check out http://www.stevesouders.com/blog/2009/06/18/simplifying-css-selectors/ on simplifying css selectors for a little better performance
hojberg
@hojberg this is an interesting link, I will see whether I find the time to work aspects from it into the answer over the next couple of days. Thanks!
Pekka
I'm curious as to why you advocate giving `body` tags a unique class rather than just an id?
Andrew Heath
@Andrew mainly because in a dynamic environment (like a CMS) using an ID could easily lead to collisions (say, a user renaming a page to "contact", leading to that name being used as the body's ID, colliding with the contact form also named "contact"). I generally recommend using IDs as sparingly as possible for that reason.
Pekka
Interesting, and thank you for the speedy reply!
Andrew Heath
Good to Know that I've been working good regarding css files ;) One of the nicest answers that I've seen!! Keep Up the Good Work.
Zuul
+4  A: 

I find the difficult thing is translating the required design for a site into a series of rules. If the site’s design is clear and rules-based, then your class names and CSS structure can flow from that. But if people are, over time, randomly adding little bits to the site that don’t make much sense, there’s not a lot you can do about that in the CSS.

I tend to organise my CSS files roughly like this:

  1. CSS reset, based on Eric Meyer’s (as otherwise I find that, for most elements, I’ve got at least one or two rules that are just resetting default browser styles. Most of my lists don’t look like the default HTML style for lists.)

  2. Grid system CSS, if the site calls for it. (I base mine on <960.gs>)

  3. Styles for elements that appear on every page (headers, footers, etc)

  4. Styles for components that are used in different places across the site

  5. Styles that are only relevant on individual pages

As you can see, most of that depends on the design for the site. If the design’s clear and organised, your CSS can be. If not, you’re screwed.

Paul D. Waite
+11  A: 

This question has been asked/answered several times over on Stack Overflow. Here are just 4 examples:

On all 4 my answer has included the advice to download and read Natalie Downe's PDF CSS Systems. (The PDF includes tons of notes not in the slides, so read the PDF!). Take note of her suggestions for organization.

Andy Ford
Thank you for the link to the PDF. I'm checking it out now.
JasCav
+1 very nice links!
Pekka
Natalie Downe’s CSS Systems is fantastic.
Paul D. Waite
+3  A: 

You should also understand the cascade, and weight, and how they work.

I notice you are using only class identifiers (div.title). Did you know that you can use IDs as well, and that an ID carries more weight than a class?

For example,

#page1 div.title, #page1 ul, #page1 span {
  // rules
}

will make all those elements share a font-size, say, or a color, or whatever your rules are. You can even make all the DIVs that are descendants of #page1 get certain rules.

As to weight, remember that the CSS axes move from most-general/lightest to most-specific/heaviest. That is, in a CSS selector an element specifier is overruled by a class specifier is overruled by an ID specifier. Numbers count, so a selector with two element specifiers (ul li) will have more weight than one with only a single specifier (li).

Think of it like digits. A 9 in the ones column is still less than a one in the tens column. A selector with an ID specifier, a class specifier, and two element specifiers, will have more weight than a selector with no ID, 500 class specifiers and 1,000 element specifiers. This is an absurd example, of course, but you get the idea. The point is, applying this concept helps you clean up a lot of CSS.

BTW, adding the element specifier to the class (div.title) is not necessary unless you are running into conflicts with other elements that have class="title". Don't add unnecessary weight, because you may need to use that weight later.

Robusto
Good explanation. I really appreciate it. (+1)
JasCav
Using IDs is bad just like using global variables in your Visual Basic code.
alpav
@alpav: Sorry, that's incorrect. IDs are a terrific way to make like elements appear differently in different parts of a page without going nuts making up new class names.
Robusto
@Robusto: Why making new ID name is harder than making new class name ?
alpav
@Robusto: making new class names is actually easier than ID names because with IDs you have to worry about global scope and with class names you need to worry only about uniqueness in local scope, same benefit as with local variables.
alpav
@alpav: Write it the way that suits you. I, for one, enjoy tremendous benefits from using IDs, and I don't mind that they have to be unique on the page. In fact, I count on it. If you think they are just an alternative to a className, you may not be ready for serious CSS yet.
Robusto
+3  A: 

My answer is high-level to address the high-level concerns you've raised in your question. There may be low-level organizational tricks and tweak you can do to make it prettier, but none of those can fix methodological deficiencies. There are several things that affect CSS explosion. Obviously the overall complexity of the site, but also things like naming semantics, CSS performance, CSS file organization, and testability/acceptability.

You seem to be on the right path with naming semantics, but it can be taken a step further. Sections of HTML that appear repeatedly on the site without structural modification (known as "modules") can be considered selector roots, and from there you can scope the internal layout relative to that root. This is the basic tenet of object-oriented CSS, and you can read/watch more about it in this talk by a Yahoo engineer.

It's important to note that this clean approach can run opposite of the concern of performance, which favors short selectors based either on id or tag name. Finding that balance is up to you, but unless you have a massive site, this should just be a guide in the back of your head reminding you to keep your selectors short. More about performance here.

Lastly, are you going to have a single CSS file for your entire site, or multiple files (a single base file used with per-page or -section files)? The single file is better for performance, but might be harder to understand/maintain with multiple team members, and might be harder to test. For testing, I recommend you have a single CSS-test page that includes every supported CSS module to test collisions and unintended cascading.

Alternatively you can have a multiple file approach, to scope the CSS rules to a page or a section. This requires the browser to download multiple files which is a performance issue. You can use server-side programming to specify and aggregate (and minify) the CSS files into a single file dynamically. But since these files are separate and the testing for them would be separate, you introduce the possibility of inconsistent look and feel across pages/sections. Thus testing becomes harder.

It's up to you to analyze the customer's specific needs, balance these concerns accordingly.

gWiz
A: 

Have a look at 1. SASS 2. Compass

Zimbabao