This Newbie’s First Impressions of Haml and Sass

Up until this past October, I was just your average web designer/developer writing markup in XHTML (with some Rails goodness mixed in), styling it with CSS, and checking it in with SVN. Life was pretty simple… well, until I needed to do something like work on a different code branch or find that damn unclosed div.

Upon joining PatientsLikeMe, I learned that I’d be shaking up this comfy part of my life as well. PatientsLikeMe is also a Rails app, but the views are built in Haml and the site’s CSS is built with Sass. (We use Git for version control, but that’s a post for another time.)

What the heck are Haml and Sass?

According to Haml’s About page, Haml is:

Haml is a markup language that’s used to cleanly and simply describe the HTML of any web document without the use of inline code. Haml functions as a replacement for inline page templating systems such as PHP, ASP, and ERB, the templating language used in most Ruby on Rails applications. However, Haml avoids the need for explicitly coding HTML into the template, because it itself is a description of the HTML, with some code to generate dynamic content.

And Sass is described on its About page as:

Sass is 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.

While it felt a bit overwhelming to learn a new way to do what I’ve been doing for years, Haml & Sass definitely make sense for me. I’m a designer/developer, but definitely approach things from more of a development side. I get just as excited (if not more) about a clean document structure and re-use of style elements as I do about a gorgeous look and feel. Anything you want to do in HTML & CSS is possible with Haml & Sass—it’s just a more efficient way of getting there. And there’s so much more!

What do Haml and Sass look like?

The best way to get what it’s all about is to take a look at some code. Here’s a codeblock of HTML/ERB, taken directly from the Haml tutorial page:

<div id="content">
  <div class="left column">
    <h2>Welcome to our site!</h2>
    <p><%= print_information %></p>
  </div>
  <div class="right column">
    <%= render :partial => "sidebar" %>
  </div>
</div>

Here’s how that block would look in Haml:

#content
  .left.column
    %h2 Welcome to our site!
    %p= print_information
  .right.column
    = render :partial => "sidebar"

Pretty badass, huh? Much cleaner. I thought I’d miss writing full markup. But I’m also a huge fan of nicely indented, properly closed markup. The fact that Haml’s indentation is what defines the document structure is awesome. You don’t have to hunt for closing </div> tags and whatnot. I recommend reading that entire tutorial (it’s quite short).

While Haml is really cool, Sass is what I’m really psyched about. I work in Sass a lot more than I work in anything else now, and I’m still discovering ways that it vastly improves my CSS development.

Here’s what a very simple bit of Sass code looks like:

h1
  height: 118px
  margin-top: 1em
.tagline
  font-size: 26px
  text-align: right

Pretty much expected, this would render as:

h1 {
  height: 118px;
  margin-top: 1em;
}
.tagline {
  font-size: 26px;
  text-align: right;
}

“Huh? What’s the benefit there?” you might ask. I mean, all it does is remove the semi-colons and braces!

Oh, but wait.

Things that make Sass kick ass

Buckle up for this part. Today, I want to tell you about three thing that will blow your CSS-writin’ mind.

  1. Nesting
  2. Variables
  3. Mixins

Nesting

In one of my recent (and favorite) style sheets, I started using much longer selectors not only to ensure my styles are targeting the right elements, but also to be visually manageable in my style sheet.

Take this block of styles targeted for a specific page on the site:

body#home.partners div#content h1 { margin-bottom: 20px; }
body#home.partners div#content h2 { background: url(../images/press-head-bg.png) repeat-x top left; border-top: 1px solid #4097E5; padding: 8px; }
body#home.partners div#content p { font-size: 90%; }
body#home.partners div#content div#main dl { position: relative; min-height: 160px; }
body#home.partners div#content div#main dt { margin-left: 170px; border-top: 2px solid #4899E9; padding: 4px 0; }
body#home.partners div#content div#main dt a { color: #000; font-weight: bold; }
body#home.partners div#content div#main dd { margin-left: 170px; font-size: 85%; }
body#home.partners div#content div#main dd.logo { position: absolute; top: 0; left: 0; margin: 0; }
body#home.partners div#content div#main dd.logo img { border: 1px solid #999; }

Yeah, I one-lined it. I’ve been into that lately. But Sass doesn’t support it (yet, but it’s coming).

One of the reasons I like one-line CSS is that it’s easy to read the selectors. But why keep typing the same things over and over? The same thing can be accomplished in Sass with this:

body#home.partners
  div#content
    h1
      margin-bottom: 20px
    h2
      background: url(../images/press-head-bg.png) repeat-x top left
      border-top: 1px solid #4097E5
      padding: 8px
    p
      font-size: 90%
    div#main
      dl
        position: relative
        min-height: 160px
        dt
          margin-left: 170px
          border-top: 2px solid #4899E9
          padding: 4px 0
          a
            color: #000
            font-weight: bold
        dd
          margin-left: 170px
          font-size: 85%
          &.logo
            position: absolute
            top: 0
            left: 0
            margin: 0
            img
              border: 1px solid #999

Longer? Yes. Easier to read? Hell yes.

This is pretty straight forward. If you indent an element under another element, you’ll chain them together. The output in CSS can get larger as you nest deeper and deeper, but the Sass file becomes much easier to manage. Your web development brethren may gasp if they peek at your stylesheet, but you’ll be able to write and manage it much faster in the Sass file.

One thing in the above code block that might look unfamiliar is the &.logo. What “&” means is “repeat the parent selector”. In this case, one parent is dd, so the selector becomes dd.logo. You can do many different things with this, such as putting &:hover after an a or even putting * html & nested beneath a selector to target IE6.

Wait, what? Mix IE hacks in with your main CSS? Yes, I realize that this invalidates your CSS and goes against some “best practices”, but trust me—it’s easier to manage. When you keep browser hacks in a separate style sheet, you forget about them until you’re actually thinking about that browser. A seemingly harmless tweak to your main stylesheet might break something in your IE stylesheet. But outta sight, outta mind and you don’t know it until a user complains. By keeping the IE hacks along with the main CSS, you can see how your change might affect other browsers.

If you’re still worried about invalidating your stylesheet, well… that means you haven’t even tried CSS3 yet. So, really, I got nothing for ya here.

In your Sass, I’ve started targeting different versions of IE along with the standard style like this:

h1
  padding: 1em
  *padding: 2em / targets both IE6 and IE7, does not target IE8
  * html &
    padding: 3em / resets IE6 in case it needs to be different from IE7

The * right before the selector will target IE6 and IE7 but leave IE8 alone (well, technically all browsers read that as an invalid line an ignore it… except for IE6 and IE7). The trusty * html hack will only target IE6. A slash, as you probably guessed, starts a comment in Sass. This IE targeting method may not be the prettiest thing in the world, but it keeps everything in one place so you easily manage all browser styling at once. When you change the padding of the h1, it provides you with a reminder to check other browsers where you served targeted tweaks.

Last thing about nesting, you can also use it for properties like font, border, margin, etc. Like so:

h1
  border:
    color: black
    style: solid
    width: 1px

That would produce:

h1 {
  border-color: black;
  border-style: solid;
  border-width: 1px;
}

Of course, you may prefer to write this out in shorthand (h1 { border: 1px solid black;), but there are times when doing it this way can come in handy.

Anyway, let’s move on to some more awesome.

Variables

There was a time when I thought variables in CSS might be the only thing that could make it any better. And variables are indeed awesome. Variables are a great way to store values that you’ll use over and over again, such as colors, fonts, graphics, or anything else reusable in your project.

Here are some variables we set for colors that indicate severity:

!severity_normal = #CCC
!severity_none = #1DAE49
!severity_mild = #FEDC32
!severity_moderate = #FF8F02
!severity_severe = #D93019

To call one of these values, simply do this:

a
  &:hover
    background-color = !severity_mild

Huzzah!

Now try this—it’ll blow your mind: Just set your target page width. Then use that variable and perform simple operations on it to calculate the widths of your layout’s columns!

!page_width = 1000px

#main
  width: !page_width * .7
#sidebar
  width: !page_width * .3

This turns into:

#main
  width: 700px;
#sidebar
  width: 300px;

Looks simple, but IMAGINE THE POSSIBILITIES! But there’s actually one more thing that will really rock your world…

Mixins

If Sass mixins were a rock band, I’d have the tee shirt. What are they? The description from the Sass tutorial says:

Mixins are one of the most powerful aspects of Sass. They allow re-use of styling – properties or even entire rules – without having to re-write them or move them into a non-semantic class.

To define a mixin, just write =mixin-name with some Sass nested underneath. To use it, write +mixin-name where you want it to be expanded.

Mixins can be incredibly simple or very complex. Here’s a pretty simple one:

=alternate_font
  font-family: 'Lucida Grande', 'Lucida Sans Unicode'
  letter-spacing: -.03em

Say you’ve set a default font on your body, but want to apply an alternate font here and there. Instead of adding those fonts every time, just put it as a mixin. This could also be done as a variable, but since we’re also tweaking the letter-spacing, it is better to do it with a mixin. The best part of mixins like this one is that they eliminate the need to add frivolous class names that are only used for style targeting.

Let’s apply it:

h1
  +alternate_header_font

And that will render as:

h1 {
  font-family: 'Lucida Grande', 'Lucida Sans Unicode';
  letter-spacing: -.03em;
}

You can also pass arguments within mixins. If you’re into rounded corners, ever get tired of defining the -moz and -webkit properties every single time?

Try this instead:

=border_radius(!radius)
  :border-radius = "#{!radius}px"
  :-moz-border-radius = "#{!radius}px"
  :-webkit-border-radius = "#{!radius}px"

Then when you want to round the corners of an element, just add this:

#sidebar
  border: 2px solid #666
  background-color: #CCC
  +border_radius(8)

That will add 8-pixel rounded corners for all (supported) browsers. I recently worked on a design that was so well-rounded you could call it Alan Trammell. This mixin alone would have been a breeze to use and very much welcomed.

Okay, one more example because this was a very handy one I used the other day. I had a couple links I wanted to place a divider pipe between. You know, the type of treatment you often see in footers. I saw that Cris had already written a mixin for it called “divider_pipe”, and it looked something like this:

=divider_pipe(!x_position=0, !y_position=50%)
  background:
    image = "url(/images/divider.gif)"
    repeat: no-repeat
  position = !x_position !y_position
  &.first
    background-image: none

You catch that? Awesome! Basically, you just apply it to the li in Sass, like this:

#footer
  ul
    li
      +divider_pipe

What that will do is place the divider on the left side of each li, but also look for an li with a class of “first” and turn off the background image for that one. Perfect! Once all our target browsers support pseudo-elements, we’ll be able to simply use a :first-child, but until then, this worked like a charm. You’ll notice you can also pass in some arguments here to alter the x- and y-positioning of the pipe on the fly.

Sass mixins can be as simple or as complex as you’d like. They can be used for just one rule you want to add over and over (without adding frivolous class names). They can be used for content boxes you use over and over that you need to receive arguments, variables, and all sorts of custom rules. Mixins are as powerful as you want to make them.

And what do I think?

Haml is pretty simple. I like it because it leads to a clean document structure, proper indenting, proper tag closing, etc. But Sass is the real life-changer, here.

I’ve gotten used to Sass enough that I keep forgetting to put semicolons in my plain ol’ CSS. While the nesting makes Sass incredibly easy to manage for the developer, it does lead to some less than beautiful output. But I think that is a fair tradeoff because it makes things so much easier to manage.

The same can be said for managing targeted browser tweaks inline with the standard Sass. It’s not the traditional way of doing things in CSS, but keeping it all together ensures less conflicts in the end.

In a way, I’ve needed to let go of some of the artificial “best practices” instilled in me while learning CSS. But the reality is that Sass comes with a whole new set of “best practices” that, in my opinion, lead to better results.

And that’s what matters most.

10 Comments

  1. On January 11th, 2010 at 9:15 am Chris Bloom said:

    I never quite understood the benefit of mixins until now. Holy Carp!

    Two questions:

    1.) I’m guessing Sass is rendered out as a normal CSS file at some point, but is it cached? And if so, is there an option for outputting it in minified format? Is it smart enough to know when the original Sass file has changed and re-render a new cached file?

    2.) In Haml, is there support for adding extra attributes to each tag?

  2. On January 11th, 2010 at 10:58 am Mark Richman said:

    @Chris, 1) Yes. Yes. Yes. 2) Yes.

  3. On January 11th, 2010 at 11:09 am Adam Darowski said:

    Thanks Mark! Yes, Chris… as Mark said…

    +yes(4)

  4. On January 11th, 2010 at 12:38 pm Scott McCracken said:

    I’ve been intrigued by Sass for a while, but admittedly haven’t really looked into it until your post. Great write-up, there are some excellent time-savers in there.

    Also, the “…so well-rounded you could call it Alan Trammell.” quote didn’t go unappreciated ;)

  5. On January 13th, 2010 at 7:49 pm Chris Bloom said:

    Thanks for the answers. I’m about to start a new project and think I’ll give Haml/Sass a try.

    I must admit I had to Google the Trammell reference. Figures it’s a baseball reference :)

  6. On January 24th, 2010 at 12:42 pm Kurt said:

    Hey Adam, thanks for the write-up on Sass! I’m going to give the similar LESS a spin and see if it helps to take the pain out of managing CSS in our projects.

    One note about the CSS on darowski.com: When I zoom in on the page (using Chrome 4.0), the text does not zoom. Zooming seems to work OK in FireFox 3.5.7, though. Maybe a Chrome bug, but I thought I’d mention it. I’ve noticed similar behavior on some of the BatchBook / BatchBlue pages, as well.

  7. On January 25th, 2010 at 9:38 am Adam Darowski said:

    Hey thanks, Kurt. And yes, once Safari 4 came out and adopted the full-page zoom, I noticed that as well. Some combination I’m using with keyword+percentage-based fonts and my layout just isn’t getting zoomed. I used the same approach for BatchBook & BatchBlue.com, so not terribly surprised. Thanks for the heads up!

  8. On January 29th, 2010 at 12:31 am Shawn K. said:

    Mmmm, I think I’m in the mood for pork.
    Haml looks delicious, I’ve read about it before but your breakdown caught my attention.

    Thanks!

  9. On February 25th, 2010 at 12:11 pm Sassy-pants « My name is Joel said:

    [...] won’t go into the syntatic sugar that makes Sass so much fun – John Long[1][2] and Adam Darowski have already done excellent jobs rounding up the high, and lower, level concepts and tricks. I [...]

  10. On June 1st, 2010 at 10:01 pm Manage Your CSS3 Tricks with Sass Mixins | PatientsLikeMe Tech Blog said:

    [...] CSS3, I also continued my lovefest with Sass. A while back on my personal blog, I wrote up my first impressions of Haml & Sass (Haml is a markup language for generating HTML while Sass is a meta-language for [...]