The Wayback Machine - https://web.archive.org/web/20131009053354/http://sass-lang.com:80/tutorial.html

Install Ruby and Sass

First of all, let’s get Sass up and running. If you’re using OS X, you’ll already have Ruby installed. Windows users can install Ruby via the Windows installer, and Linux users can install it via their package manager.

Once you have Ruby installed, you can install Sass by running

gem install sass

Your First Sass Stylesheet

We’ll start out by creating a very simple SCSS file. Since SCSS is an extension of CSS3, our first file will start out as plain CSS. Open up a new file called style.scss in your text editor, and add the following:

/* style.scss */
#navbar {
  width: 80%;
  height: 23px;
}

To translate this Sass file into a CSS file, run

sass --watch style.scss:style.css

Now whenever you change style.scss, Sass will automatically update style.css with the changes. Later on when you have several Sass files, you can also watch an entire directory:

sass --watch stylesheets/sass:stylesheets/compiled

Features

Although it’s nice that every CSS file is a valid SCSS file, that’s not why you’re learning about SCSS. You’re learning because it offers more than CSS. SCSS provides all sorts of useful features on top of CSS. This tutorial will walk you through some of the most fundamental ones, along with examples that you can add to your style.scss and play with.

Nesting

Often when writing CSS, you’ll have several selectors that all begin with the same thing. For example, you might have “#navbar ul”, “#navbar li”, and “#navbar li a”. It’s a pain to repeat the beginning over and over again, especially when it gets long.

Sass allows you to avoid this by nesting the child selectors within the parent selector.

/* style.scss */

#navbar {
  width: 80%;
  height: 23px;

  ul { list-style-type: none; }
  li {
    float: left;
    a { font-weight: bold; }
  }
}
/* style.css */

#navbar {
  width: 80%;
  height: 23px; }
  #navbar ul {
    list-style-type: none; }
  #navbar li {
    float: left; }
    #navbar li a {
      font-weight: bold; }

Notice how the output is formatted to reflect the original nesting of the selectors. This is the default CSS style, but there are other styles for all sorts of CSS formatting preferences. There’s even one for compressing the CSS as much as possible!

Be aware that nesting selectors does have a cost in terms of code size and maintainability. You don’t want to exactly match the nesting of the HTML; that makes it very difficult to update your CSS when the HTML changes in small ways. It’s generally a good idea to prefer only two or three levels of nesting.

You can also nest properties, so you don’t have to repeat stuff like “border-left-” all the time.

/* style.scss */

.fakeshadow {
  border: {
    style: solid;
    left: {
      width: 4px;
      color: #888;
    }
    right: {
      width: 2px;
      color: #ccc;
    }
  }
}
/* style.css */

.fakeshadow {
  border-style: solid;
  border-left-width: 4px;
  border-left-color: #888;
  border-right-width: 2px;
  border-right-color: #ccc; }

Parent References

What about pseudoclasses, like :hover? There isn’t a space between them and their parent selector, but it’s still possible to nest them. You just need to use the Sass special character &. In a selector, & will be replaced verbatim with the parent selector.

/* style.scss */

a {
  color: #ce4dd6;
  &:hover { color: #ffb3ff; }
  &:visited { color: #c458cb; }
}
/* style.css */

a {
  color: #ce4dd6; }
  a:hover {
    color: #ffb3ff; }
  a:visited {
    color: #c458cb; }

Variables

Sass allows you to declare variables that can be used throughout your stylesheet. Variables begin with $ and are declared just like properties. They can have any value that’s allowed for a CSS property, such as colors, numbers (with units), or text.

/* style.scss */

$main-color: #ce4dd6;
$style: solid;

#navbar {
  border-bottom: {
    color: $main-color;
    style: $style;
  }
}

a {
  color: $main-color;
  &:hover { border-bottom: $style 1px; }
}
/* style.css */

#navbar {
  border-bottom-color: #ce4dd6;
  border-bottom-style: solid; }

a {
  color: #ce4dd6; }
  a:hover {
    border-bottom: solid 1px; }

Variables allow you to re-use colors, sizes, and other values without repeating yourself. This means that changes that should be small, such as tweaking the coloring or the sizing, can be done in one place, not all over the stylesheet.

Operations and Functions

In addition to just using variable values as they’re defined, you can also modify and combine them using math and useful predefined functions. This allows you to compute element sizing and even coloration dynamically.

The standard math operations (+, -, *, /, and %) are supported for numbers, even those with units. For colors, there are all sorts of useful functions for changing the lightness, hue, saturation, and more.

/* style.scss */

#navbar {
  $navbar-width: 800px;
  $items: 5;
  $navbar-color: #ce4dd6;

  width: $navbar-width;
  border-bottom: 2px solid $navbar-color;

  li {
    float: left;
    width: $navbar-width/$items - 10px;

    background-color:
      lighten($navbar-color, 20%);
    &:hover {
      background-color:
        lighten($navbar-color, 10%);
    }
  }
}
/* style.css */

#navbar {
  width: 800px;
  border-bottom: 2px solid #ce4dd6; }
  #navbar li {
    float: left;
    width: 150px;
    background-color: #e5a0e9; }
    #navbar li:hover {
      background-color: #d976e0; }

Interpolation

Variables can be used for more than just property values. You can use #{} to insert them into property names or selectors.

/* style.scss */

$vert: top;
$horz: left;
$radius: 10px;

.rounded-#{$vert}-#{$horz} {
  border-#{$vert}-#{$horz}-radius: $radius;
  -moz-border-radius-#{$vert}#{$horz}: $radius;
  -webkit-border-#{$vert}-#{$horz}-radius: $radius;
}
/* style.css */

.rounded-top-left {
  border-top-radius: 10px;
  -moz-border-radius-top: 10px;
  -webkit-border-top-radius: 10px; }

Mixins

Mixins are one of the most powerful Sass features. They allow re-use of styles – properties or even selectors – without having to copy and paste them or move them into a non-semantic class.

Mixins are defined using the “@mixin” directive, which takes a block of styles that can then be included in another selector using the “@include” directive.

/* style.scss */

@mixin rounded-top-left {
  $vert: top;
  $horz: left;
  $radius: 10px;

  border-#{$vert}-#{$horz}-radius: $radius;
  -moz-border-radius-#{$vert}#{$horz}: $radius;
  -webkit-border-#{$vert}-#{$horz}-radius: $radius;
}

#navbar li { @include rounded-top-left; }
#footer { @include rounded-top-left; }
/* style.css */

#navbar li {
  border-top-left-radius: 10px;
  -moz-border-radius-topleft: 10px;
  -webkit-border-top-left-radius: 10px; }

#footer {
  border-top-left-radius: 10px;
  -moz-border-radius-topleft: 10px;
  -webkit-border-top-left-radius: 10px; }

Arguments

The real power of mixins comes when you pass them arguments. Arguments are declared as a parenthesized, comma-separated list of variables. Each of those variables is assigned a value each time the mixin is used.

Mixin arguments can also be given default values just like you’d declare them normally. Then the user of the mixin can choose not to pass that argument and it will be assigned the default value.

/* style.scss */

@mixin rounded($vert, $horz, $radius: 10px) {
  border-#{$vert}-#{$horz}-radius: $radius;
  -moz-border-radius-#{$vert}#{$horz}: $radius;
  -webkit-border-#{$vert}-#{$horz}-radius: $radius;
}

#navbar li { @include rounded(top, left); }
#footer { @include rounded(top, left, 5px); }
#sidebar { @include rounded(top, left, 8px); }
/* style.css */

#navbar li {
  border-top-left-radius: 10px;
  -moz-border-radius-topleft: 10px;
  -webkit-border-top-left-radius: 10px; }

#footer {
  border-top-left-radius: 5px;
  -moz-border-radius-topleft: 5px;
  -webkit-border-top-left-radius: 5px; }

#sidebar {
  border-top-left-radius: 8px;
  -moz-border-radius-topleft: 8px;
  -webkit-border-top-left-radius: 8px; }

@import

Stylesheets can get pretty big. CSS has an @import directive that allows you to break your styles up into multiple stylesheets, but each stylesheet takes a separate (slow) HTTP request. That’s why Sass’s @import directive pulls in the stylesheets directly. Not only that, but any variables or mixins defined in @imported files are available to the files that import them.

Sass has a naming convention for files that are meant to be imported (called “partials”): they begin with an underscore. Let’s create a partial called _rounded.scss to hold our rounded mixin.

In order to support both .scss and .sass files, Sass allows files to be imported without specifying a file extension. That means we can just import "rounded", rather than "rounded.scss".

/* _rounded.scss */

@mixin rounded($vert, $horz, $radius: 10px) {
  border-#{$vert}-#{$horz}-radius: $radius;
  -moz-border-radius-#{$vert}#{$horz}: $radius;
  -webkit-border-#{$vert}-#{$horz}-radius: $radius;
}
/* style.css */

#navbar li {
  border-top-left-radius: 10px;
  -moz-border-radius-topleft: 10px;
  -webkit-border-top-left-radius: 10px; }

#footer {
  border-top-left-radius: 5px;
  -moz-border-radius-topleft: 5px;
  -webkit-border-top-left-radius: 5px; }

#sidebar {
  border-top-left-radius: 8px;
  -moz-border-radius-topleft: 8px;
  -webkit-border-top-left-radius: 8px; }
/* style.scss */

@import "rounded";

#navbar li { @include rounded(top, left); }
#footer { @include rounded(top, left, 5px); }
#sidebar { @include rounded(top, left, 8px); }

Further Reading

This should be enough to get you up and running with Sass, but there’s a lot more to explore: check out the Sass reference for a full account of what Sass can do, including all the options you can set and how to use it as a Rails/Rack plugin.

If you need any help or if you just want to chat about Sass, hop on the #sass IRC channel on irc.freenode.net (if there’s no one there, the #compass channel is also a good place to try). Questions can also be asked on the Sass mailing list.