Cooking With Sass

Hello again. This week I’ve been getting to grips with Sass and seeing what I could do with it. Sass (a rather charming acronym of Syntactically Awesome StyleSheets) is a component of the Haml plugin for Ruby. Where Haml deals with the markup of HTML, Sass deals with the markup of CSS. It describes itself as

… a meta-language on top of CSS that’s used to describe the style of a document cleanly and structurally, with more power than flat CSS allows. Sass both provides a simpler, more elegant syntax for CSS and implements various features that are useful for creating manageable stylesheets.

Sounds good! These ‘features’ include variable assignment, auto nesting of rules and a basic scripting language for stuff like conditional statements and loops.

Assuming you have Ruby and Rails setup already, getting Sass up and running is pretty straight-forward. Follow the reference manual and you won’t go too far wrong. By default, Sass will look for files in public/stylesheets/sass and compile the generated stylesheet(s) in public/stylesheets/

Now, for a quick project I thought it might be a good idea to make an easily adjustable grid system based on 960gs. Yes, yes, there is already a custom CSS generator available on there, but just for fun, I’m going to make this one em based. Using em based measurements will let older browsers that don’t have a full-page zoom features (and those, like me, that insist on use ‘zoom text only’) to scale up the grid size with text size.

To transfer over the 960gs to Sass would be pretty simple, you could manually copy the rules and format to fit Sass conventions, or you could use the css2sass utility, like so,

css2sass 960.css 960.sass

I am going to create this from scratch though. It helps at this point (in fact, essential…) to have an idea of the grid that you want to create- the number of columns, colum width and gutter sizes. As we will be working with ems, it helps to define a base font-size that we will be working from also, generally being equal to the font-size of your standard paragraph text. In this instance, I am working on a design with an 18px underlying grid, 14px base font-size, 12 columns, 63px wide with 18px gutters (9px either side). We will come back to these numbers shortly.

A quick analysis of the 960gs shows that it does 5 things: Set the container width; set the width, margins and float of each column size; nullify left/right margins of the first/last nested columns respectively; set the prefix widths and set the suffix widths. I have omitted for this test a few of the features found in 960gs, such as the push/pull widths (I tend not to use them very often) and clearfix rules (preferring to locate them elsewhere).

We can translate the nullify left/right margin directly…

/*===============
  CSS
===============*/
.alpha{
  margin-left: 0;
}
.omega{
  margin-right: 0;
}

/*===============
  SASS
===============*/
.alpha
  margin-left: 0

.omega
  margin-right: 0

As you can see, the translation from CSS to Sass is pretty simple, you don’t need any curly braces or terminating semi-colons, just indent the rule with a soft-tab (two spaces) on a new line. Do be careful though, there must be a space after the colon separating the property and value. So far, so simple. For the other phases, we can use the feature of Sass to make our job a lot easier. In order to do this, we should setup a few variables to work from. The first thing is the base font size, here set at 14px. To set a variable in Sass, we simple add an exclamation mark to the start of your variable name and assign using an equals sign, like thus !varName = value. Sass takes 4 types of variables: numbers, strings, colors and boolean. We set our base font-size like this

!baseUnit = 14px

From this, I found it very useful to set our underlying grid size (18px) and define it as an em value. We can then use this a base for most of our dimensions later on. We divide 18 by 14 to find to correct ratio (1.28571529) and set this as our value. We can define the number of columns at this point too.

!gridUnit = 1.28571529 em
!numCols = 12

From these initial variables we set our column width and gutter width.

!colWidth = 3.5 * !gridUnit  //( 3.5*1.28571529em = 4.5em * 14px = 63px)
!gutterWidth = 0.5 * !gridUnit

These initial variables are all we need to set, as everything else we can calculate from them, meaning also that to change the grid, we just need to change these corresponding values. Want a 6 column layout? Just set !numCol = 6.

Now the fun part. Using the variables above, we can set the container width. The width is equal to the number of columns, multiplied by the column width plus gutter width (left and right). In Sass, we write that as

.container_12
  font-size = !baseUnit
  width= !numCols * (!colWidth + 2*!gutterWidth)
  margin: auto

Note that to assign a value containing variables or operations to a property we use the equals (=) instead of a colon (:). I add the font-size here for added security that we work from that for our em calculation. We can use the interpolation feature of Sass to dynamically change the CSS selector to reflect that of a variable, so instead of .container_12, we can use .container_#{!numCols}.

.container_#{!numCols}
  font-size = !baseUnit
  width= !numCols * (!colWidth + 2*!gutterWidth)
  margin: auto

This becomes a very useful feature as you will see. Instead of writing for each column size…

grid_1
 width = ..

grid_2
  width = ..

we can use the interpolation feature along with the looping feature to do the work for us. All we need, is to determine a formula for the width of a specific column size (which turns out to be the desired column size multiplied column width, added to the desired column size less 1, multiplied by the gutter width (left+right). Keep that in mind!). A Sass loop is pretty straight forward, requiring a counter, start value and end value. So for us, we start our loop like so

@for !i from 1 through !numCols
  .container_#{!numCols}
    .grid_#{!i}

where !i is our counter and !numCols is our end value. This loop when run will basically spit out

.container_12
  grid_1

.container_12
  grid_2

.. and so on until

.container_12
  grid_12

from this, we can just slap in our rule for the width of a column, along with the floats and margins (gutter), and we are almost there.

@for !i from 1 through !numCols
  .container_#{!numCols}
    .grid_#{!i}
      font-size: !baseUnit
      width = width = (!i * !colWidth) + ((!i - 1)*(2*!gutterWidth))
      float: left
      display: inline
      margin
        left: !gutterWidth
        right: !gutterWidth

While we have a loop running, we can go ahead and put in the dimensions of our suffixes and prefixes here as well, though only for column sizes less that our number of columns. This means using an if statement which handles as you would expect it. So while in the loop and inside our container selector, we can write…

    @if !i < !numCols
      .prefix_#{!i}
        padding-left= (!i * !colWidth) + (!i * 2 * !gutterWidth)
      .suffix_#{!i}
        padding-right= (!i * !colWidth) + (!i * 2 * !gutterWidth)

add this together with all the stuff before, and what we have is this

!numCols = 12
!baseUnit = 14px
!gridUnit = 1.28571529em
!colWidth = !gridUnit * 3.5
!gutterWidth = !gridUnit * 0.5

.container_#{!numCols}
  font-size= !baseUnit
  margin-left: auto
  margin-right: auto
  width= !numCols * (!colWidth+(2*!gutterWidth))

@for !i from 1 through !numCols
  .container_#{!numCols}
    .grid_#{!i}
      font-size= !baseUnit
      width = (!i * !colWidth) + ((!i - 1)*(2*!gutterWidth))
      float: left
      display: inline
      margin:
        left= !gutterWidth
        right= !gutterWidth
    @if !i < !numCols
      .prefix_#{!i}
        padding-left= (!i * !colWidth) + (!i * 2 * !gutterWidth)
      .suffix_#{!i}
        padding-right= (!i * !colWidth) + (!i * 2 * !gutterWidth)

.container_#{!numCols} .alpha
  margin-left: 0

.container_#{!numCols} .omega
  margin-right: 0

As this is em based, you do need to be a bit more careful with setting font-sizes or assigning a grid_xx to anything with a font-size larger than the base value (such as headlines). As a basic rule, don’t set a font-size on grid_xx and wrap any elements that may have a different font-size in a grid_xx rather than assigning it directly.

There are probably many ways to improve this, so please do let me know your thoughts using the comments below!

No Comments

RSS feed for comments on this post. TrackBack URL

No comments yet.

Leave a comment

Preview: