The power of SASS

Alexandre SimõesSoftware Architect
CERTIFIED EXPERT
Published:
Updated:
Styling your websites can become very complex.
Here I'll show how SASS can help you better organize, maintain and reuse your CSS code.

A bit of history

SASS appeared in 2006 and stands for Syntactically Awesome Stylesheet and have evolved a lot since then.

The main point that can cause some confusion is the difference between SASS and SCSS. SASS is the tool name that supports two syntaxes:
  1. SassScript (also known as "the intended syntax") that has an indented format much like Haml. The main problem here is that you cannot reuse your existing CSS.
  2. SCSS (Sassy CSS) came later, and pretty much replaced the SassScript, with a syntax that is CSS on steroids. This means that you can just drop normal CSS in a SCSS file and start optimizing from there.
I don't want to close this section without mentioning LESS. LESS is somewhat similar to SASS but lacks some functionalities. I invite you to compare both and you'll see that SASS does everything LESS does and much more.


Before we start

This article doesn't cover all the functionalities provided by SASS. My idea is to show that SASS serves a much broader purpose than the mere nested selectors feature for which it's most known. Please make sure you take your time to ready the complete documentation available here.
 

Browsers only know CSS

This is a very important point. Browsers know nothing about SASS; they can only read CSS syntax. This means that SASS needs to be compiled into normal CSS using the compiler of your choice. The best choice depends on your development environment.

If you're using Visual Studio, your best option is Visual Studio Web Essentials. Among many other features, it seamlessly integrates with the IDE and generates your CSS files on the fly.

Other compilers are available for virtually any platform; just make sure you include the compilation process at file-save time or, at the very least, at build time.
 

Learning SASS by example

I'm going to show you the key features of SCSS while I step-by-step build a fancy grid menu. I advise you test this step-by-step code as you go. To keep you away from setup complications I suggest you use one of the many online SCSS online test tools like SassMeister of jsFiddle.

What I propose we do is a configurable matrix of links, rotated by 45 degrees. The end result should look like this:
EE-SASS-Final-Result.png
The base HTML is the following:
 

<ul class="fancygrid">
                        <li><a>Item 1</a></li>
                        <li><a>Item 2</a></li>
                        <li><a>Item 3</a></li>
                        <li><a>Item 4</a></li>
                        <li><a>Item 5</a></li>
                        <li><a>Item 6</a></li>
                      </ul>

Open in new window


1. SASS is just CSS

As said before, it's just CSS on steroids. This means that all your current CSS code will be 100% reused.


2. Nested selectors

This is probably one of the most known SASS features. What this means is that you can start nesting your selectors instead of duplicating the parent all over the place. Below you'll see that the SASS representation defines the inner <li> styles nested in the <ul> definition.

SASS
 
.fancygrid {
                        position: relative;
                        margin: 0;
                        padding: 0;
                        display: block;
                        list-style-type: none;
                        li {
                          display: block;
                          float: left;
                          margin: 0;
                          padding: 0;
                          border: solid 1px #f00;
                          width: 50px;
                          height: 50px;
                        }
                      }

Open in new window


The CSS result of the above
 
.fancygrid {
                        position: relative;
                        margin: 0;
                        padding: 0;
                        display: block;
                        list-style-type: none;
                      }
                      
                      .fancygrid li {
                        display: block;
                        float: left;
                        margin: 0;
                        padding: 0;
                        border: solid 1px #f00;
                        width: 50px;
                        height: 50px;
                      }

Open in new window



3. Variables

Let's start with the fun stuff, Variables! Variables names must start with $ and their value can be anything that is a valid CSS property value (more on this later).

How many times do you repeat colors and sizes across your styles? How painful is it when the client want a different shade of yellow and you have to change it everywhere? Forget about all that and store these common values variables. Let's refactor our simple code to include them.
 
.fancygrid {
                        $width: 50px;
                        $height: 50px;
                        $hmargin: 10px;
                        $vmargin: 10px;
                        position: relative;
                        margin: 0;
                        padding: 0;
                        display: block;
                        list-style-type: none;
                        
                        li {
                          display: block;
                          float: left;
                          margin: 0 $hmargin $vmargin 0;
                          padding: 0;
                          border: solid 1px #f00;
                          width: $width;
                          height: $height;
                        }
                      }

Open in new window



4. Mixins

What if we could encapsulate some CSS logic in function-like blocks of code? This is what Mixins are for. Basically, you define a function, that can accept arguments, and the result will be the properties that will be added to the selector where you are using it. A good example is a function that applies rounded corners to an element:
 
@mixin border-radius($radius) {
                        -webkit-border-radius: $radius;
                        -moz-border-radius: $radius;
                        -ms-border-radius: $radius;
                        border-radius: $radius;
                      }

Open in new window


Another example is a mixin that rotates elements by a specified value:
 
@mixin rotate($degrees) {
                        -ms-transform: rotate($degrees);
                        /* IE 9 */
                        -webkit-transform: rotate($degrees);
                        /* Chrome, Safari, Opera */
                        transform: rotate($degrees);
                      }

Open in new window


Let's add these Mixins to our code:


.fancygrid {
                        $width: 50px;
                        $height: 50px;
                        $radius: 5px;
                        $rotate: 45deg;
                        $hmargin: 10px;
                        $vmargin: 10px;
                        
                        @mixin border-radius($radius) {
                          -webkit-border-radius: $radius;
                          -moz-border-radius: $radius;
                          -ms-border-radius: $radius;
                          border-radius: $radius;
                        }
                        
                        @mixin rotate($degrees) {
                          -ms-transform: rotate($degrees);
                          -webkit-transform: rotate($degrees);
                          transform: rotate($degrees);
                        }
                        
                        position: relative;
                        margin: 0;
                        padding: 0;
                        display: block;
                        list-style-type: none;
                        
                        li {
                          display: block;
                          float: left;
                          margin: 0 $hmargin $vmargin 0;
                          padding: 0;
                          border: solid 1px #f00;
                          width: $width;
                          height: $height;
                          @include border-radius($radius);
                          @include rotate($rotate);
                        }
                      }

Open in new window



5. You can do Math!

This one is also very handy. With SCSS you can calculate the value of your properties instead of being forced to set only static values. You can do pretty much any mathematical basic operation, and this is enough for it to get quite complex :) You can also combine variables in your math so that the result depends on them.
Something like:
 
width: $width * 2;

Open in new window


I'm not anything to our example just now, move on!


6. Loops

Yes, we can also do loops in SCSS and they are really handy. Loops can be defined in three ways: @for, @each or @while.
Their names a very much self-explanatory and they can be used as follows:
 
/* @for */
                      @for $i from 1 through 3 {
                        .item-#{$i} { width: 2em * $i; }
                      }
                      
                      /* @each */
                      @each $animal in puma, sea-slug, egret, salamander {
                        .#{$animal}-icon {
                          background-image: url('/images/#{$animal}.png');
                        }
                      }
                      
                      /* @while */
                      $i: 6;
                      @while $i > 0 {
                        .item-#{$i} { width: 2em * $i; }
                        $i: $i - 2;
                      }

Open in new window


Let's now revamp our demo and take advantage of the math and loops.
The final HTML
 
<ul class="fancygrid">
                        <li class="pos-0-0">
                          <a href="#1"><span>Item 1</span></a>
                        </li>
                        <li class="pos-0-1">
                          <a href="#1"><span>Item 2</span></a>
                        </li>
                        <li class="pos-0-2">
                          <a href="#1"><span>Item 3</span></a>
                        </li>
                        <li class="pos-1-0">
                          <a href="#1"><span>Item 4</span></a>
                        </li>
                        <li class="pos-1-1">
                          <a href="#1"><span>Item 5</span></a>
                        </li>
                        <li class="pos-1-2">
                          <a href="#1"><span>Item 6</span></a>
                        </li>
                      </ul>

Open in new window


The final SCSS
 
.fancygrid {
                        $textColor: #000;
                        $width: 50px; // item width
                        $height: 50px; // item height
                        $radius: 5px; // corner rounding radius
                        $rotate: 45deg; // item rotation
                        $hmargin: 25px; // horizontal margin
                        $vmargin: 25px; // vertical margin
                        $top: 0; // initial top position
                        $left: 0; // initial left position
                        $rows: 2; // number or rows
                        $cols: 3; // number of columns
                        
                        @mixin border-radius($radius) {
                          -webkit-border-radius: $radius;
                          -moz-border-radius: $radius;
                          -ms-border-radius: $radius;
                          border-radius: $radius;
                        }
                        
                        @mixin rotate($degrees) {
                          -ms-transform: rotate($degrees);
                          -webkit-transform: rotate($degrees);
                          transform: rotate($degrees);
                        }
                        
                        @mixin position($row, $col) {
                          left: $left + $width/2 + $width*$col + $hmargin*$col;
                          top: $top + $height/2 + $height*$row + $vmargin*$row;
                        }
                        
                        position: relative;
                        margin: 0;
                        padding: 0;
                        display: block;
                        list-style-type: none;
                        
                        li {
                          display: block;
                          position: absolute;
                          margin: 0 $hmargin $vmargin 0;
                          padding: 0;
                          border: solid 1px #f00;
                          width: $width;
                          height: $height;
                          @include border-radius($radius);
                          @include rotate($rotate);
                          
                          /* generate the classes dynamically for all
                             the available positions. This directly
                             depends on the $cols and $rows variables
                             declared above. If you want more rows or columns
                             just configure it accordingly. */
                          @for $r from 0 through $rows {
                            @for $c from 0 through $cols {
                              &.pos-#{$r}-#{$c} {
                                @include position($r, $c);
                              }
                            }
                          }
                        
                          a {
                            display: block;
                            text-decoration: none;
                            display: table-cell;
                            height: $height;
                            width: $width;
                            text-align: center;
                            vertical-align: middle;
                            color: $textColor;
                            span {
                              display: block;
                              // rotate the text back the same value
                              @include rotate(-$rotate);
                            }
                          }
                        
                        }
                      }

Open in new window

 

There's a lot more to know

My intention here was not to replicate the SASS documentation but to show that SASS is a lot more than nested selectors.
At the end, you can build full CSS frameworks with this that you can reuse across all your projects. Please refer to the documentation to fully know the language.


Honorable mentions:


@if

It's easy to imagine that you'll end up needing some sort of conditions.
 

@import

Allows you to reference multiple SCSS files, allowing you to better organize your code and pick only the pieces that you really need.


@Extend

Inheritance of selectors. Imagine that you need to create a new selector that is exactly like the one that already exists but you need to add or change a couple of properties. You can simple inherit (extend) from the existing and start from there.


The End

I hope I managed to, at least, pique your curiosity. For simple styles the advantage is not evident but when things start getting complex you'll see that treating your CSS in a "OOP" way makes the whole thing much easier to maintain.
3
2,876 Views
Alexandre SimõesSoftware Architect
CERTIFIED EXPERT

Comments (3)

Marco GasiFreelancer
CERTIFIED EXPERT
Top Expert 2010

Commented:
Finally some clear words about SASS: thank you very mutch for this article: I'm going to read the other two :-)
Alexandre SimõesSoftware Architect
CERTIFIED EXPERT

Author

Commented:
Thanks Marco,
let me know if after reading the three articles you still feel that something is missing.
It will sure come as a nice subject for a sequel on this series.

Cheers!
Alex
Marco GasiFreelancer
CERTIFIED EXPERT
Top Expert 2010

Commented:
I f I'll have some idea I'll tell you for sure :-)
Cheers
Marco

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.