Susy: A Compass Plugin

Susy Tutorial

Once you've installed everything we can start building our grid. I'll walk you through the steps. I'm starting with the assumption that you already know CSS and the Compass/Sass syntax. If you don't, check out Chris Eppstein's great intro.

For a brief overview of Susy's philosophy and goals, see the README.

On Susy's Terms

Here are the terms to understand for following along and using Susy:

Customizing your Grid System

So let's get started. We're going to build a website for Susy. This website. It's a simple site but it covers everything you need to get started on your own.

Create yourself a Compass project using Susy:

compass -r susy -f susy susy_tutorial

Inside the susy_tutorial directory, create an index.html file. You can grab my source.

Start in your _base.sass file (in the src directory). That's where you set all your defaults.

To create a grid, set the !grid_unit (units that your grid is based in), !total_cols (total number of columns in your grid), !col_width (width of columns), and !gutter_width (width of gutters) variables.

The default values are 16 columns, 4em column widths, 1em gutters and side gutters that match the internal ones. But we want a 10 column grid, with 5em columns, 2em gutters and 1em side-gutters.

Take a look at our target site again, this time with a grid overlay.

So we'll set our grid like this:

!grid_unit = "em" 
!total_cols = 10 
!col_width = 5 
!gutter_width = 2
!side_gutter_width = 1

Of course, designing in em's, we'll want to get your font sizes set to make this all meaningful. Do that by assigning a pixel value (without the units) to !base_font_size_px and !base_line_height_px. Susy will convert those to a percentage of the common browser default (16px) and apply them to your grid.

The default values here are 12px fonts with an 18px line-height. For us:

!base_font_size_px = 14 
!base_line_height_px = 21

_base.sass also has everything you need for setting default font families, colors to reuse throughout, and default styles for all those elements that ought have a default (but don't because of the reset).

We can leave most of that as it is for now, but let's fill in a few of the most important defaults. We want some colors to choose from, and defaults for links and paragraphs.

So let's add some colors:

!text = #332016
!light = #CC8866
!links = #4CAAC0

And style the links:

a
  &:link, &:visited
    :color= !links
    :text-decoration none
  &:focus, &:hover, &:active
    :color= !light
    :border-bottom
      :width= px2em(2) + "em"
      :style dashed

(Susy provides the convenience function px2em, which can approximate a pixel value in ems, given our chosen !base_font_size_px. Here we want the dashed bottom border to be 2 pixels wide at the default font size, but we size it in ems - the result here will be .1429em. Susy's math functions return bare numbers, so we add "em" ourselves).

And we'll add a bit of margin to our paragraphs:

p
  :margin-bottom 1.5em

That's it. You can look around at the other defaults and set what you like, or juse use mine.

Making Semantic Grids

First the explanation:

Then we do it. In screen.sass, we'll start by declaring our intent to use Susy, and our container:

body
  +susy

#page
  +container

That wasn't hard. You might ask why I didn't nest #page inside of body, as is so tempting and easy with Sass. It's part personal preference and part Natalie Downe's voice in my head. Don't nest when you don't need to. It keeps your output code much cleaner.

While we're at it, why don't we get the fonts and text colors going right from the start?

#page
  +container
  +sans-family
  :color= !text

Perfect. Take a look at the results. So far we have:

Laying Out The Components

It's time to lay out our grid components. We'll just work our way through the DOM, starting with our brand header (#brand). We can refer back to our target site with a grid overlay to see what we need. Looks like our branding gets an entire row to itself, with the content starting one row in. For the sake of argument, let's say we want the header content contained within the middle 8 columns - one in from each end. That means it will be an 8 column element, with 1 column prefixed and one suffixed, for a total of 10 columns - the full width.

#brand
  +columns(8)
  +prefix(1)
  +suffix(1)

Since it spans both the first and last columns in the context we'll need to add:

+alpha
+omega

Or we would have to, but there are several shortcuts available to us. To declare something as both alpha and omega we can just declare it as full:

+full

There is also a shorcut for prefix and suffix additions (+pad), so we can simplify down to:

#brand
  +columns(8)
  +pad(1,1)
  +full

Since we don't have an image in there yet, let's move the text over to line up with the future placement of our main content area. By turning the h1 link into a grid element and prefixing a padding of one column, we can move the text without any effect on the image that will replace it (using the Compass utility +replace-text, though I'll leave the implementation that as an exercise for you to figure out). To line it all up with the content below it, we'll assign it 5 columns in a context of 8, with the extra 3 split between a prefix of 1 and a suffix of 2 - giving it a full span.

h1 a
  +columns(5,8)
  +pad(1,2,8)
  +full(8)

There is one 'gotcha' in the way Susy handles context. Direct children of your container (such as #brand in this case) must not declare a context. If you do, your side-gutters will be ignored. At every nested layer below that, even if the context hasn't changed, you must declare a context or it will try to add side-gutters again. That means even if you have one nested element wrapping the rest at full width and not changing the context, that wrapper does not get a context but its descendants do, even where that context is the same as the full page.

For example, these will not work:

#page
  +container
  .inner
    +columns(10,10)

#page
  +container
  .inner
    +columns(10)
    #brand
      +columns(10)

This will work:

#page
  +container
  .inner
    +columns(10)
    #brand
      +columns(10,10)

Remember that if your side gutters or columns ever seem the wrong size.

We're only worried about structure for now, so the header is done. Let's move on to the navigation (#nav). The nav spans 2 columns, including the first column in it's context.

#nav
  +columns(2)
  +alpha

Done. The content (#content, which includes both #description and #credit) spans the remaining 8 columns, including the last one.

#content
  +columns(8)
  +omega

Done. #description spans 5, including the first; #credit spans 3 including the last. Both are in a nested context of 8, which we now need to pass on:

#description
  +columns(5,8)
  +alpha(8)

#credit
  +columns(3,8)
  +omega(8)

Done and done. All we have left is the footer (#site-info) spanning the full width, but only using the right 8 columns:

#site-info
  +columns(8)
  +prefix(2)
  +full

Nested in the footer are .license and .styles, so let's put them in place. I'm going to say that each should match the width of the element visually above it on the page. So .license will span 5 columns including the first in its context of 8, and .styles will span 3 including the last.

p.license
  +columns(5,8)
  +alpha(8)
p.styles
  +columns(3,8)
  +omega(8)

And we're done. That's it. That's what Susy does. The details of making it pretty are left as an exercise for the reader, and have more to do with Compass than Susy.