Advertisement

Mastering the 960 Grid System

by
Student iconAre you a student? Get a yearly Tuts+ subscription for $45 →

We're already familiar with the 12- and 16-column variants of 960.gs, but did you know that a 24-column alternative exists too? In this article, you'll master the 960 grid system by dissecting the 24-column version demo. If you've only used 960gs before for Photoshop mockups, consider this your lucky day. By the end of this article, you'll be able to convert your designs to HTML and CSS in no time at all.


Introduction

A 960 Grid System Master—that's what you'll be after you've gone through this article. And, although we're going to use the 24-column variant of 960gs, you'll completely understand how the two older types (i.e., 12- and 16-columns) work too, by applying the same principles you'll learn here. But first, take a good look at the 24-column demo in the 960gs site, as it's all we'll need in our leap towards mastery of this popular CSS framework.


A Look at the 24-Column Demo

We first need to check the HTML code of the demo, so view its source—if you're using Chrome, Firefox, or Opera, just press ctrl+U; if you're using Internet Explorer, change your browser! :) (on the Mac, use cmd+U for Firefox and opt+cmd+U for Safari and Opera; Chrome only does the right-click option). Keep the HTML source code window on your desktop, as we're going to refer to it from time to time.

Next, you'll need to download the 960.gs files (if you haven't done so yet), and open the uncompressed CSS file 960_24_col.css. We must do this because the demo's CSS is compressed, and will be difficult to inspect. (If you're the masochistic type, feel free to use the demo's CSS instead.

That's pretty much all we need to prepare, aside from a semi-functioning brain. Now you'll find that the demo page holds the key to completely understanding the grid system, and we'll start by examining its three sections.


Inspecting the Framework: The Demo's Three Sections

The three sections consist of the following:

1: Top Section

First, we have a top area that shows two columns for each row, where the left column grows wider as the right column gets narrower, until they are equal in size.

top section of the 24-column 960 demo

2: Middle Section

Next, we have a middle section that shows a 30px square progressively moving from left to right, while whitespace before and after it extends the row to take up the whole 960px width.

mid-section of the 24-column 960 demo

3: Bottom Section

Finally, there's a bottom section that shows two rows of rectangles with different sizes, which split the 960px width in two halves.

bottom section of the 24-column 960 demo

Believe it or not, understanding completely what the assigned classes behind these columns do is all you'll ever need to get a firm grasp of 960 grid system. Isn't that great? Let's examine each section further.


Top section: grid_1 to grid_24 classes

Peeking at the source code of this section shows us that, first, before any of the grid_xx classes were assigned, the class container_24 was given to the overall wrapping div:

    
<div class="container_24"> 
	<h2> 
		24 Column Grid
	</h2>
	...
</div>
<!-- end .container_24 -->

The importance of this class cannot be overemphasized—it partly dictates the width of the columns where a grid_xx class is assigned. And as you might have guessed, it also “divides” the 960px width into 24 columns.

(Similarly, putting container_12 or container_16 at the top will “divide” the width into 12 and 16 columns, respectively. The word divide is in quotes because it doesn't actually do that; you'll see later how this process is achieved.)

Moving on, you'll notice that the top-most row has a single div with a class of grid_24. The remaining rows in the top section have two divs each: the left divs range from class grid_1 up to grid_12, and the right divs range from grid_23 down to grid_12; the sum of the two classes in each row is 24.

     
<div class="grid_24"> 
	<p> 
		950
	</p> 
</div> 
<!-- end .grid_24 --> 

<div class="clear"></div> 

<div class="grid_1"> 
	<p> 
		30
	</p> 
</div> 
<!-- end .grid_1 --> 

<div class="grid_23"> 
	<p> 
		910
	</p> 
</div> 
<!-- end .grid_23 --> 

<div class="clear"></div> 

<div class="grid_2"> 
	<p> 
		70
	</p> 
</div> 
<!-- end .grid_2 -->

<!-- ... -->

<div class="grid_11"> 
	<p> 
		430
	</p> 
</div> 
<!-- end .grid_11 --> 

<div class="grid_13"> 
	<p> 
		510
	</p> 
</div> 
<!-- end .grid_13 --> 

<div class="clear"></div> 

<div class="grid_12"> 
	<p> 
		470
	</p> 
</div> 
<!-- end .grid_12 --> 

<div class="grid_12"> 
	<p> 
		470
	</p> 
</div> 
<!-- end .grid_12 --> 

<div class="clear"></div>

This is how the assigned grid_xx classes would look like if we tried to visualize each div's class name:

top section of the 24-column 960 demo with grid classes labeled

You might have noticed in the code that after the last div in a row, we have an empty div with a class of clear. Ignore it for now, we'll deal with it later.

Next, let's take a look at what happens behind the scenes, i.e., in the CSS, when we assign the container_24 class:

        .container_24 {
            margin-left: auto;
            margin-right: auto;
            width: 960px;
        }

As you can see, this class, which was assigned to the overall wrapping div of the document, centers our work area and gives it a 960px width. Easy enough.

Next, here are the grid_xx classes, which were placed on the main divs of the top section:

        
        .grid_1,
        .grid_2,
        .grid_3,
        ...
        .grid_23,
        .grid_24 {
            display: inline;
            float: left;
            margin-left: 5px;
            margin-right: 5px;
        }

We see that the grid_xx classes give the columns left and right margins of 5px each, which forms a 10px gutter when you place the columns side-by-side. This in turn is achieved by floating them all to the left.

Also, they are given a display of inline, to prevent the Double Margin Float Bug from being triggered in our dearly-beloved browser. (Apparently, it is triggered when you float an element that has margins assigned to it.)

top section: what the CSS does

Lastly, we have the descendant selectors formed by a combination of container_24 and grid_xx classes:

  
        .container_24 .grid_1 {
            width: 30px;
        }
        .container_24 .grid_2 {
            width: 70px;
        }
        ...
        ...
        .container_24 .grid_23 {
            width: 910px;
        }
        .container_24 .grid_24 {
            width: 950px;
        }

As you can see, these CSS declarations are the ones that actually determine the width of the columns where a grid_xx class is assigned. This is how assigning container_24 at the top “divides” the width into 24 columns— the pre-set width sizes are assigned according to which container_xx class a grid_xx class is combined with.

the container and grid classes in 24-col combined sets the width of the columns

For comparison purposes, here is how its counterpart CSS declarations in the 16-column variant looks like:

         
        .container_16 .grid_1 {
            width: 40px;
        }
        
        .container_16 .grid_2 {
            width: 100px;
        }
        
        .container_16 .grid_3 {
            width: 160px;
        }
the container and grid classes in 16-col combined sets the width of the columns

If you compare the HTML source code of the demo for the 12- and 16-columns with the 24-column demo, you'll notice that there is no difference in how the grid_xx classes were assigned. And now you know why this is so—it's not the grid_xx class that determines the width of the columns, but its combination with a container_xx class, as shown in the CSS above.

Another thing worth noting here is the actual size of each container when you assign a grid_xx class. Although it's labeled 30, 70, 110, and so on in the demo, it's actually 10px more because of the left and right margins on either side of the container.

actual size of the containers is 10px more than its label

As you can see,

  • grid_1 has a width of 30px + 10px horizontal margins (total width: 40px)
  • grid_2 has a width of grid_1 (40px) + 30px width + 10px margins (total width: 80px)
  • grid_24 has a width of grid_23 (920px) + 30px width + 10px margins (total width: 960px)

Seeing it this way satisfies the math we have for the width: that 24 40px-wide columns is equal to 960px (i.e., 40px * 24 = 960px).

This view more accurately shows what the CSS actually does to the markup. Although the container's size is really just 30px, 70px, 110px, and so on (as it is labeled in the demo), it helps to know that the horizontal margins are the reason why the sum of the widths for each row do not equal to 960px. (It only amounts to 940px, except for the first row, assigned a grid_24, which spans 950px. The "lost" 20px for all the other divs is accounted for by the leftmost and rightmost 5px margins, and the 10px gutter between the 2 columns for each row.)

But here's the more practical thing to remember: As long as you use the 24-column psd template when you create your designs (or the 12- or 16-column psd templates, for that matter), you can just count the number of columns you want for a particular design element, use that number for your grid_xx class, and the column is set. For example, if your logo takes up four columns, then give its containing div a grid_4 class.

Here's an example of how to use it:

example application of grid_xx classes

Although the 960.gs site (shown above) actually uses the 12-column variant, we could just as well overlay the 24-column pattern on it and it will still fit the layout perfectly (because the 24-column version is, of course, just the 12-column version with columns divided by two).

As you can see, knowing that we have a 960px width divided into 24 columns makes life easier, as we only need to line up our design elements along the edges of the columns, count the number of columns they occupy, set that as our grid_xx class's number, and we're done.

But what if you want a lot of empty spaces in your design? Or what if you want to center a small design element, and just have white spaces around it?

Enter the prefix_xx and suffix_xx classes.


Middle Section: prefix_xx and suffix_xx classes

If you check the markup for the middle section, what you'll see are variations of this code:

<div class="grid_1 prefix_xx suffix_xx"> 
    <p>
        30
    </p> 
</div>

...where prefix_xx + suffix_xx = 23. (That is, 0 + 23, 1 + 22, 2 + 21, 3 + 20, and so on..)

What's happening here?

First, you'll notice that each row class assignments amount to 24 columns (grid_1 + combined values of prefix_xx and suffix_xx classes, which is 23).

Next, you'll see that the prefix_xx classes are in ascending order (from 1 to 23) while the suffix_xx classes are descending (from 23 to 1). Also, when prefix_xx or suffix_xx has a value of 23, it doesn't have a counterpart suffix_xx or prefix_xx class, because it no longer needs it (value is already 23).

Lastly, each of these units is 30px-wide, and as we've seen in the grid_xx classes above, they also have 10px horizontal margins.

classes added for the 30px boxes

We already know that assigning an element a grid_1 class gives it a 30px width and 5px paddings on either side. But what does the prefix_xx and suffix_xx classes do?

As you may have already guessed, they give additional left (prefix_xx) and right (suffix_xx) padding, increasing the size of a grid_xx class unit. Thus, prefix_1, prefix_2, and prefix_3 will give your element left paddings of 40px, 80px, and 120px, respectively; while the same amount of paddings are given to its suffix_xx counterparts, but in the opposite side.

     
.container_24 .prefix_1 {
    padding-left: 40px;
}        
.container_24 .prefix_2 {
    padding-left: 80px;
}

...

.container_24 .suffix_1 {
    padding-right: 40px;
}

.container_24 .suffix_2 {
    padding-right: 80px;
}

For whitespace in your designs, just add the prefix_xx and suffix_xx classes. They lock up your content to a certain width (determined by the grid_xx class you assign), while the space on either side in filled up with padding.

additional horizontal paddings in grid_xx units

For a simple example, let's pretend again that the 960.gs homepage is using the 24-column variant, and that the twitter-bird graphic is the logo of the site.

suffix class in use: 960 gs homepage

We can see that it occupies three columns, so we give it a grid_3 class. Let's also assume that there are no other elements along its row. We would therefore also give it a suffix_21 class (3 + 21 = 24), since the additional padding needs to span the whole width.

Obviously, if there are other elements on that row, we need to adjust the suffix_xx class to create some space for another element that spans a few grid_xx classes (e.g. a search form). Also, depending on where your design elements are located relative to the left edge of the row, you might also need to add a prefix_xx class.

Always remember: the numbers used in the classes for each row (whether grid, prefix, or suffix) should be equal to 24.

Next, we'll perform a bit of ‘magic,’ as the next set of classes allow your content to appear differently than what the markup predicts it would.


Bottom Section: pull_xx and push_xx Classes

For this section, if you're not using Firefox at the moment, I'd like to ask you to switch to it temporarily, as you'll understand the next concepts better with Chris Pederick's Web Developer Toolbar (WDT) extension for Firefox. (If you haven't installed it yet, now's the time to download and install it. I understand there's already a Google Chrome version of the WDT, but in my opinion, it's nowhere near its Firefox counterpart.)

Once you're running Firefox with the WDT already installed, go back to the 24-column demo page, and scroll down to the very bottom. You'll see the two groups of boxes I showed you a while ago—different-sized, yet fitting together to form this last section of the demo.

Now check out the HTML code for this section:

<div class="grid_12 push_12"> 
    <div class="grid_6 alpha"> 
        <p> 
            230
        </p> 
    </div> 
    <!-- end .grid_6 .alpha --> 

    <div class="grid_6 omega"> 
        <p> 
            230
        </p> 
    </div> 
    <!-- end .grid_6 .omega --> 

    <div class="clear"></div> 

    <div class="grid_1 alpha"> 
        <p> 
            30
        </p> 
    </div> 
    <!-- end .grid_1 .alpha --> 

    <div class="grid_11 omega"> 
        <p> 
            430
        </p> 
    </div> 
    <!-- end .grid_11 .omega --> 

    <div class="clear"></div> 

</div> 
<!-- end .grid_12 .push_12 --> 

<div class="grid_12 pull_12"> 
    <div class="grid_1 alpha"> 
        <p> 
            30
        </p> 
    </div> 
    <!-- end .grid_1 .alpha --> 

    <div class="grid_11 omega"> 
        <p> 
            430
        </p> 
    </div> 
    <!-- end .grid_11 .omega --> 

    <div class="clear"></div> 

    <div class="grid_6 alpha"> 
        <p> 
            230
        </p> 
    </div> 
    <!-- end .grid_6 .alpha --> 

    <div class="grid_6 omega"> 
        <p> 
            230
        </p> 
    </div> 
    <!-- end .grid_6 .omega --> 

    <div class="clear"></div> 

</div> 
<!-- end .grid_12 .pull_12 --> 

<div class="clear"></div>

Compare it again to what you see on the demo page.

What's happening here? Shouldn't the first group of boxes (230-230-30-430) be shown before the last group (30-430-230-230), as in the markup?

Well, that's the power of the push_xx and pull_xx classes. But before we go into them, go to the WDT, click the Information button, and choose Display Div Order, just to make sure that you're correctly seeing how the CSS affects the markup.

web developer toolbar's display div order command chosen

Here's a screenshot of what you should see:

bottom section with display div order command activated

I needed to show this to demonstrate that the two groups are divided into left and right sides, and not top and bottom. That perception error is easy to make (as I did) because: (1) we're used to seeing div groups that stretch the whole 960px width; and (2) the two groups have similar-sized boxes that are easy to confuse with each other.

(Nathan Smith, the 960gs creator, could have probably used boxes with different sizes—e.g. 70-390-190-270 and 230-230-30-430—to achieve the same effect and would have avoided the potential confusion, but he didn't....)

But now that you've seen how the first group (as it appears in the markup) was “pushed” and how the second group was “pulled” by these classes, check out the CSS to see how they're doing it:

    
.push_1, .pull_1,
.push_2, .pull_2,
...
.push_22, .pull_22,
.push_23, .pull_23 {
    position: relative;
}

...

.container_24 .push_1 {
    left: 40px;
}

.container_24 .push_2 {
    left: 80px;
}

...

.container_24 .push_22 {
    left: 880px;
}

.container_24 .push_23 {
    left: 920px;
}

...

.container_24 .pull_1 {
    left: -40px;
}

.container_24 .pull_2 {
    left: -80px;
}

...

.container_24 .pull_22 {
    left: -880px;
}

.container_24 .pull_23 {
    left: -920px;
}

First, giving these two classes to HTML elements positions those elements relatively, so that we could move the divs to the left, right, top, or bottom relative to where it would normally occur in the document. (More on CSS positioning here.)

Next, in combination with the container_24 class, the pull_xx classes give the div a negative left padding, which makes it possible to “pull” the div's content to the left. On the other hand, the push_xx classes, as expected, does the opposite and gives the div a (positive) left padding to “push” its content to the right (by giving way to the left padding).

bottom section with display div order command activated

“But why the hassle?” you might ask. “Why not just put them in the correct order in the markup in the first place, so you won't have to use these unnecessary classes?”

Good questions. The answer lies in the pursuit of having semantic and accessible markup—our designs should not force the markup to a structure that doesn't make sense or isn't up to standards when the stylings are turned off. And CSS has been proven to handle such situations elegantly—it lets us achieve the look of our designs regardless of how the markup was written (well, largely).

In the 960gs site, Nathan Smith shows the header as a good example of how he used these classes:

960.gs header

On the surface, we might think the markup will show the Twitter logo first, then the Download link, and finally the 960 logo. But that wouldn't be semantic—the title of the site (i.e. 960 logo) should come in first. And as you probably know, this arrangement also has SEO benefits. So, the markup for the header actually goes something like:

<body> 
<div class="container_12"> 
    <h1 class="grid_4 push_4"> 
        960 Grid System
    </h1> 
    <!-- end .grid_4.push_4 --> 
    <p id="description" class="grid_4 pull_4"> 
        <a href="#">Download</a> - Templates: Acorn Fireworks, Flash, ...
    </p> 
    <!-- end #description.grid_4.pull_4 -->

As you can see, the logo does come in first, and after it, the download link. (The markup for the Twitter logo is found after the footer, was given an id of twitter, and is absolutely-positioned. It wasn't given a 960.gs class, so we won't concern ourselves with it.)

You also saw in the markup (as predicted) that the logo was pushed and the download link section pulled. To visualize it more clearly:

960.gs header labeled with classes

And that's how you use the push or pull classes—know that they either give your divs a negative or positive left padding, then “pull” or “push” your content according to the number of columns you need your content to be pulled or pushed.

There's one last set of classes that are integral to 960.gs—and they let you create complex layouts. A column that spans several rows, for example. Let's tackle them next.


alpha and omega Classes

If you've read tutorials or articles on 960.gs before, you probably already know by now that the alpha and omega classes cancel the horizontal paddings set by grid_xx classes. And most likely you also know that their primary use lies when you have grid_xx classes inside nested divs.

For the benefit of those who don't know yet, let's go to our CSS and see what these classes do to the elements they are assigned to:

.alpha {
	margin-left: 0;
}

.omega {
	margin-right: 0;
}

Pretty straightforward—they simply zero out the left (alpha) and right (omega) margins. And as we've seen a while ago, when we assign an element a grid_xx class, we automatically give it horizontal margins of 5px on both sides. With nested divs, we don't want to double these margins, so we give an alpha or an omega class, or both, accordingly.

bottom section div group showing alpha and omega classes

A nested div that's touching the left edge of its parent div would be given the alpha class. Similarly, the omega class is assigned to the nested div that's placed on the parent div's right edge. But what if we have a nested div that touches both edges of its parent div? That's right, we assign both classes to it.

Let's move on to an example so that you can see how it's done.

Though not shown in the 960.gs demo, here's an instance of how a complex layout is achieved with the aid of the alpha and omega classes (and nested divs with grid_xx classes):

blocks of content to demonstrate alpha & omega and nested divs

Here we have columns that span several rows on both sides, with rows and boxes in the middle. You can also visualize it as a typical 3-column layout; but for our example, we're just using 15 columns. Of course, you can easily expand it to 24 columns.

The key to creating layouts like these in 960.gs is to:

  1. Remember that 960.gs makes the layout possible by floating divs to the left.
  2. Create your nested divs from those initial floated divs—. This means you'll have floated divs within floated divs.

Here's one way of approaching our layout: group them into three columns first, and assign them the appropriate grid_xx classes:

blocks of content to demonstrate alpha & omega and nested divs

Next, assign the additional grid_xx classes for the nested divs (note that we don't have any nested div for the right column):

blocks of content to demonstrate alpha & omega and nested divs

Since we have at least two levels of grid_xx classes inside nested divs, we also need to add the alpha and omega classes appropriately:

blocks of content to demonstrate alpha & omega and nested divs

The nested divs inside the left column touches both edges of its parent div, so we need to add both alpha and omega. The same holds true for the divs with grid_8 classes in the middle section. But each grid_4 div on top only has to have alpha or omega, since it only touches either the left or the right edge of its parent div.

As you may have concluded from this simple example, you can nest divs with grid_xx classes as deep as you want (if your design demands it), as long you correctly mark them up, and give them the right 960.gs classes, so that they are floated correctly and any excess margins are canceled.

And speaking of floats, the last group of 960.gs classes, though not unique to 960.gs, make it all possible—they clear the floats that are automatically created when you assign a grid_xx class.


Leveling the Field: The clear Classes

Earlier, we noticed this in the markup—every div that was given a grid_xx class, that was also the last div for its row, was followed by an empty div with a class of clear.

    
<div class="grid_5"> 
    <p> 
        190
    </p> 
</div> 
<!-- end .grid_5 --> 

<div class="grid_19"> 
    <p> 
        750
    </p> 
</div> 
<!-- end .grid_19 --> 

<div class="clear"></div> 

<div class="grid_6"> 
    <p> 
        230
    </p> 
</div> 
<!-- end .grid_6 --> 

<div class="grid_18"> 
    <p> 
        710
    </p> 
</div> 
<!-- end .grid_18 --> 

<div class="clear"></div>

The no-brainer reason for this is that we need to clear floated divs, because once we float them, they no longer take up space, causing the elements below it to be “pulled up,” which ultimately leads to a broken layout.

As we've seen in the demo, a solution for this potential problem is to place an extra non-semantic div with a class of clear, which does the following:

.clear {
    clear: both;
    display: block;
    overflow: hidden;
    visibility: hidden;
    width: 0;
    height: 0;
}

The code above is basically Nathan Smith's own solution to the problem, as discussed in his blog. A lot of web designers don't have any issues with it, except probably for standardistas who might cringe at the thought of using extra non-semantic divs in the markup for a styling problem.

Thankfully, Nathan Smith also included the clearfix solution in the 960.gs CSS, first discussed on PositionIsEverything.net. It does away with the extra div, as you can place it alongside the grid_xx classes and achieve the same effect:

<div class="grid_5"> 
    <p> 
        190
    </p> 
</div> 
<!-- end .grid_5 --> 

<div class="grid_19 clearfix"> 
    <p> 
        750
    </p> 
</div> 
<!-- end .grid_19 --> 

<div class="grid_6"> 
    <p> 
        230
    </p> 
</div> 
<!-- end .grid_6 --> 

<div class="grid_18 clearfix"> 
    <p> 
        710
    </p> 
</div> 
<!-- end .grid_18 -->

That's the same example markup above with the extra divs removed, and the clearfix class added. It will do the same thing, so you can choose this method of clearing if you find it to your liking. Here's the CSS for it:

.clearfix:after {
    clear: both;
    content: '';
    display: block;
    font-size: 0;
    line-height: 0;
    visibility: hidden;
    width: 0;
    height: 0;
}
/*
The following zoom:1 rule is specifically for IE6 + IE7.
Move to separate stylesheet if invalid CSS is a problem.
*/

* html .clearfix,
*:first-child+html .clearfix {
    zoom: 1;
}

The code might be a bit different from what you're used to. This is because Nathan Smith based it on a blog entry by Jeff Star, which supposedly updates the original clearfix hack, to do away with code intended for a browser that's now extinct (i.e. IE for macs), and tweaks it for newer ones (i.e. IE6 and IE7).


Conclusion

Using just the 24-column demo of 960.gs (and in some instances, the 960.gs site itself), I've shown you how each of its classes work and how you could use them in converting your 960-based designs into HTML and CSS.

Every section in the demo imparts lessons to be learned, and once you see what the classes do to your markup by examining the CSS, the mystery of 960.gs vanishes, and you gain a better understanding of what happens behind the scenes. You might even find new ways of using the classes, since you now know what they do.

Applying your newfound knowledge becomes easy, because once you've set your columns using 960.gs, you'll just have to assign id's to the divs (as the situation warrants) as hooks to further adjust the divs' paddings or the sizes of its text inside.

Advertisement