logo image Faisal Rahman
ID EN
My profile picture taken in the summer Faisal Rahman

Level Up CSS with Sass


For those of you who frequently work with Cascading Style Sheets (CSS), you’ve surely felt at some point that writing CSS is exhausting work. From the need to rewrite nested selectors; writing compatibility prefixes like -moz-*, -ms-*, or -webkit-*; to all sorts of constant calculated values that are difficult to manipulate. You may have even wondered why CSS feels ‘primitive’ for lacking features like nesting, functions, and so on.

Worry not — let’s get acquainted with Sass, aka Syntactically Awesome Style Sheets. Sass is a preprocessor for CSS, which means we write our styling in Sass and then build it into CSS. Sass has many features that make writing CSS much easier.

Installation

Sass was originally written in the Ruby programming language and available as the sass gem. However, there is also a library written in C/C++, namely libSass, which can be used with wrappers in various programming languages. This time we’ll use the Sass wrapper for Node.js to try out Sass.

Make sure you already have Node and NPM installed on your system. Then we’ll install Sass as a global package with NPM.

$ npm install -g sass

Once the installation is complete, confirm that the sass command is registered correctly.

$ which sass

If that command does not produce an error, we’re ready to play with Sass code. Let’s create a styles.scss file to try compiling Sass to CSS.

$ touch styles.scss
$ vim styles.scss # use your preferred text editor
// styles.scss

#header {
  &-black {
    background-color: #000;
  }
}
$ sass styles.css

We’ll see the compiled output directly in our terminal’s standard output.

#header-black {
  background-color: #000;
}

To make it easier to experiment with Sass, we can run sass in watch mode with the --watch flag. Let’s open a new terminal session and run the command below.

sass --watch styles.scss output.css

Now Sass will immediately compile every change to our styles.scss file into the output.css file.

Sass Features

Sass has many features that make writing CSS easier for us. Here are some of them.

Nesting

As we already did in the example above, Sass allows us to nest our CSS code to make our code more concise and grouped.

// styles.scss
.panel {
  width: 480px;

  ul {
    list-style: none;
  }

  &--tight {
    width: 240px;
  }
}
/* output.css */

.panel {
  width: 480px;
}

.panel ul {
  list-style: none;
}

.panel--tight {
  width: 240px;
}

Note the use of the & operator for concatenating a tag at the top level of a rule. Using nesting like this makes it easier to organize CSS code in our application.

Variables

Sass also allows us to organize various values into variables.

// styles.scss

$font-stack: Helvetica, sans-serif;
$color-primary: #99eecc;

h1 {
  font-family: $font-stack;
  color: $color-primary;
}
/* output.css */

h1 {
  font-family: Helvetica, sans-serif;
  color: #99eecc;
}

Both declaring and calling variables is done with the $ symbol.

Operators

Sometimes we struggle to determine values that are relative to other values in CSS — for example, the small font size is 50% of the large font size, and so on. Sass supports the use of operators for cases like these.

//styles.scss

$font-size-base: 1rem;

h1 {
  font-size: 1.5 * $font-size-base;
}

h2 {
  font-size: $font-size-base;
}

small {
  font-size: $font-size-base / 2;
}
/* output.css */

h1 {
  font-size: 1.5rem;
}

h2 {
  font-size: 1rem;
}

small {
  font-size: 0.5rem;
}

Mixin

For rules that are repeated or reusable, we can use the mixin feature, declared with the @mixin syntax and called with the @includes syntax. For example, in this case we’ll create a mixin that adds webkit and mozilla extensions to transform.

// styles.scss

@mixin transform($property) {
  -webkit-transform: $property;
  -ms-transform: $property;
  transform: $property;
}

.rotate-90 {
  @includes transform(rotate(90deg));
}
/* output.css */

.rotate-90 {
  -webkit-transform: rotate(90deg);
  -ms-transform: rotate(90deg);
  transform: rotate(90deg);
}

The mixin syntax belongs to the group of at-rules syntax. In addition to mixin, there are also other at-rules syntaxes such as @use, @import, @warn, and others. Visit the Sass documentation page for a complete list.

Looping with @each and @for

As we saw in the variables section above, variables in Sass can contain a collection of values, not just a single value. In Sass terminology, a variable that holds many values is called a List.

We can loop over the values inside a list using the @each at-rule with the syntax shown below.

// styles.scss

$widths: 240, 480, 960;

@each $width in $widths {
  .container-#{$width} {
    width: #{$width}px;
  }
}
/* output.css */

.container-240 {
  width: 240px;
}

.container-480 {
  width: 480px;
}

.container-960 {
  width: 960px;
}

Besides @each, we can also use @for for looping with an index.

// styles.scss

$base-spacing-unit: 6;

@for $i from 1 through 4 {
  .margin-top-#{$i} {
    margin-top: #{$i * $base-spacing-unit}px;
  }
}
```css
/* output.css */

.margin-top-1 {
  margin-top: 6px;
}

.margin-top-2 {
  margin-top: 12px;
}

.margin-top-3 {
  margin-top: 18px;
}

.margin-top-4 {
  margin-top: 24px;
}

There are still many other features that Sass has, which make it easier to write and organize our CSS code — even enabling us to build a CSS framework with ease! You can visit the Sass documentation page for complete documentation of all the features Sass has to offer.