Click here to Skip to main content
Click here to Skip to main content

Tagged as

Getting SASSy with CSS

, 25 Jul 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
This article describes the syntax of SASS through discussing the problems it tries to resolve

Introduction

In this article I would like to introduce a few of the features of SASS (Syntactically Awesome StyleSheets). SASS allows you to pro grammatically define several aspects of stylesheets, "compiling" down to standard CSS. To demonstrate this I will do this through a refactoring exercise of a pre-existing CSS file, to show the sorts of problems SASS overcomes. Hopefully this will prove useful as a reference as well as an introductory how to. As this is an introduction to SASS I will just introduce the syntax, I don’t want to cover some of the finer aspects such as configuring SASS for caching or output style etc. 

Background

In general this topic is aimed at beginners at SASS, but you should know HTML and CSS reasonably well for this article to be of any use. The following is a list of resources you may find useful.

A Note About LESS

Many of the concepts apply to LESS, a similar CSS pre-processor language. I prefer the syntax of the basics of LESS as it feels more "css-ish", but for much the same reasons as this article, I think SASS pips it to the post. Either is a good choice however. Less can be found at http://lesscss.org/ .

Another reason I am using SASS is that is used in a website I have just started working on. As such my exposure to SASS is pretty limited and in writing this article I both to firm up what I have covered so far and to help promote the technology itself. When I started to look at SASS-like CSS generation, it is one of the few technologies that immediately screamed "this is a no-brainer to adopt", obviously with the caveat that the project you are working on is capable of using it.

Setting Up

The first item ticked off my to-do list was to create an MVC3 application as the sample code. If you don’t know how MVC3 works, should not be a problem: the generated HTML is what is important on the mark-up side. I will not reference the MVC3 view at all, I could just as easily used an HTML document. I have included the generated html (and the original css) in a solution folder called “Vanilla HTML and CSS” in the sample code, so you can refer to these if you are unsure about MVC3 and Razor. Running the application gives:

Getting SASS

The easiest way is to do this via NUGET (which can be installed from http://nuget.org/) package, first open the package manager console from the visual studio IDE:

Then, in the console window copy/type the following command:

install-package sassandcoffee

Nuget will install SASS into your project, you will be prompted to install definition files, select yes. You could also use the “Manage NuGet Packages for Solution” option if you prefer a GUI, search for "sassandcoffee".

At this point it is worth installing "Mindscape Web Workbench" which provides intellisense, formatting and other editor support for SASS. Close Visual Studio, download Workbench from here and open the .vsix file to install. You need only do this once for your Visual Studio installation.

Using SASS

The first thing that we need to understand is that CSS can be used directly with SASS, doing this is as simple as renaming the “.CSS “ file to “.SCSS”. If you installed Workbench the icon will like this change:

Running the app produces the same output as the earlier screenshot. The scss file is "compiled" down to a css which is used by the site. 

The eagle-eyed amongst you will have noted file extension is scss rather than sass. There is an older syntax based on indentation which uses the .sass extension. While terse, it is not as natural to a web developer as the scss syntax: vanilla css is not valid in a .sass file but is valid in a .scss file. I will not cover the sass syntax as I see no compelling reason to use it in new development work. The .scss files follow css syntax much more closely.

The really eagle-eyed amongst you will have noticed that I did not edit the reference to the css in the html header and the page still rendered. In an ASP.NET Project, Workbench "Compiles" the .scss file into a css when it is saved in Visual Studio. This has the added benefit that when the application is deployed to the server, the server does not need to do this at runtime and there is no performance hit to speak of. 

OK, we've spent a little while and are still at square one, so what is the excitement about?

Variables

The CSS for the default MVC project is fairly well structured, however one instructive thing is the comment bang at the top of the file: 

/*----------------------------------------------------------
The base color for
this template is #5c87b2. If you'd like
to use a different
color start by replacing all instances of
#5c87b2 with your
new color.
----------------------------------------------------------*/

If you want to change the base colour to, say, pink you need to do a search and replace! SASS can handle it more elegantly: we just define a variable and use it:

$base-color:
#FFA0A0; //Define a pink base colour in place of the blue
body
{
    background-color: $base-color;
    …
}

This is worth going through: The $ symbol tells SASS that there is a variable. $base-color: #FFA0A0; sets the variable to a rather fetching pink. background-color: $base-color; sets the background colour of the to the value of the parameter value. Notice that as part of SASS c-style single line comments are available!

The only other place the base colour is used in this instance is the in the bottom border of the menu:

ul#menu
{
    border-bottom: 1px $base-color solid;
    …
}

Now we only need to change the base-color variable to change the whole page. I want to darken this border so it stands out more. SASS has many built in functions  one of which darkens. I will also make the border wider to make it more visible: 

ul#menu
{
    border-bottom: 5px darken($base-color, 33%) solid;
    …
}

Rendering produces:

We are not limited to colours. We can set a variable to many things, for example the much of the text is based on em sizes, for example the headers, and perform operations on them, for example setting font heights according to a base size.

h1, h2, h3, h4, h5,
h6
{
    font-size: 1.5em;
    … 
}
h1
{
    font-size: 2em;
   … 
}
p, ul
{
  …
    line-height: 1.6em;
}

etc, becomes 

$base-text-size:
1em;
h1, h2, h3, h4, h5,
h6
{
    font-size: $base-text-size + 0.5;
     …
}
h1
{
    font-size: $base-text-size + 1;
    …
}
p, ul
{
   …
    line-height: $base-text-size + 0.6;
}

Notice that I performed an operation on the variable here, additionally I did not need to specify the unit (in this case em), SASS worked it out for me! 

How Do I Read the Generated CSS To Debug

One thing you  may have spotted is the need to see what is being generated. There are two methods, both very easy. The first (available with workbench) is to expand the tree under the .scss file, the generated css is there. The second method is to enter the url of the referenced stylesheet into the browsers as if SASS were not in use. For the default MVC3 app it is http://localhost:nnnn/Content/Site.css where nnnn is the assigned port number, in the sample app this is set to 1999.  

One really nice feature is that, if you make a syntax error workbench puts a report into the css. Suppose I miss the terminating ; on the base colour parameter declaration:

$base-color: #FFA0A0

The page will render without any styling: SASS could not produce the stylesheet. If you navigate to the css path as above, a handy error message is produced:

/* Syntax error: Invalid CSS after
"body": expected selector or at-rule, was "{"
on line 9 of C:\Users\Keith\documents\visual
studio 2010\Projects\SassExample\SassExample\Content\Site.scss
Use --trace for backtrace.
*/

Creating Chunks of CSS Properties: Mixins

Mixins are like super variables, the allow you to set several properties in one go.  In the app I want to lighten the header and the footer, and give them rounded edges. Some css/scss I could use is: 

border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
background-color: lighten($base-color, 10%); 

The first three properties allow cross browser support via web kits while the CSS3 specification is implemented. The final line lightens the background color by 10% through a SASS function. I could put this into both the header and footer css sections, but it seems to be the sort of thing we’d want to achieve often. The first step is to abstract out to a mixin:

@mixin round-corner
{
    border-radius: 5px;
    -moz-border-radius: 5px;
    -webkit-border-radius;
    background-color: lighten($base-color, 10%);
}

Now we include  the mixin where we want it to be applied 

#header
{
    …
    @include round-corner();
}
#footer
{
    …
    @include round-corner();
}

Rendering the page produces:  

 

OK there are a few things here.  We can easily foresee the re-use of the rounded corners mix in for other elements with less or more rounded corners. In the screenshot the footer is against a white background, I do not want it to be so dark, and as it has no content the corners are too large. I can still keep my single mixin by parameterising both the corner radius and the amount to lighten by:

@mixin round-corner ($radius, $lightenAmount)
{ 
    border-radius: $radius;
    -moz-border-radius: $radius;
    -webkit-border-radius: $radius;
    background-color: lighten($base-color, $lightenAmount);
}

And now we just provide the values where it is used:

#header 
{
    …
    @include round-corner(10px, 10%);
}
#footer
{
    … 
    @include round-corner(5px, 5%);
}

Here are the results:  

The @ before the @mixin and @import statements indicates that the statement is a directive. We will introduce further directives later in this article. 

Structuring CSS 

Nesting 

So far what we have achieved is pretty useful, in the interests of the DRY (Don’t Repeat Yourself) alone this is good. Now we can look at re-structuring the css itself. Let us take a look at the css for the menu system: 

ul#menu
{ 
    border-bottom: 5px darken($base-color,33%) solid;
    padding: 0 0 2px;
    position: relative;
    margin: 0;
    text-align: right;
}
ul#menu li
{
    display: inline;
    list-style: none;
}
ul#menu li#greeting
{
    padding: 10px 20px;
    font-weight: bold;
    text-decoration: none;
    line-height: 2.8em;
    color: #fff;
}

This is pretty standard stuff, but has a few shortcomings: I have selectors for ul#menu, ul#menu li and ul#menu li#greeting. Through all this, I’m repeating (at least) ul#menu. The other problem is that although the styles are related, this is not clearly reflected in the css structure. I am used to this now,  but when I first started out in web development I found it unsatisfactory, and all too easy to make a hard to trace typo in the selector. SASS allows us to nest css selectors in a .scss file, for example the ul#menu and its child list item: 

ul#menu 
{ 
    border-bottom: 5px darken($base-color,33%) solid;
    padding: 0 0 2px;
    position: relative;
    margin: 0;
    text-align: right;
    li
    {
        display: inline;
        list-style: none;
    }
}

I no longer need to include the ul#menu before the child list item. The css for these elements generated by SASS is semantically and syntactically the same as before, but the nesting in the .scss file ties the elements in a more obvious way and the risk of mis-typing a compound selector is now reduced.  Nesting is not only one level deep, I can nest further elements, if I add the greeting:

ul#menu 
{ 
    border-bottom: 5px darken($base-color,33%);
    padding: 0 0 2px;
    position: relative;
    margin: 0;
    text-align: right;
    li
    {
        display:inline;
        list-style: none;
        #greeting                           
        {
            padding: 10px 20px;
            font-weight: bold;
            text-decoration: none;
            line-height: 2.8em;                              
            color: #fff;
        }
    }                          
}

Looking at the generated css highlights a gotcha with nesting. The ID #greeting needs to be immediately after the li but the generated css has a space: ul#menu li #greeting. To overcome this, we need to use the parent selector &  before the greeting, so the above becomes

ul#menu 
{ 
    border-bottom: 5px darken($base-color,33%) solid;
    padding: 0 0 2px; 
    position: relative; 
    margin: 0; 
    text-align: right; 
    li
    {
        display: inline;
        list-style: none;
        &#greeting
        {
            padding: 10px 20px;
            font-weight: bold;
            text-decoration: none;
            line-height: 2.8em;                              
            color: #fff;
         } 
    } 
}

Now the generated CSS is as expected. The parent selector is more often used for pseudo-classes, such as a:hover, a:link etc  were we’d expect to see something like:

a 
{ 
    … 
    &:hover
    { 
        … 
    } 
    &:link 
    { 
        … 
    }
}

Property Nesting 

In addition to the standard nesting available above, we can nest properties, a good example is setting font properties, as in the styling for the body:

body
 {
  …
  font-size: 75%;
  font-family: Verdana, Tahoma, Arial, "Helvetica Neue";
  …
 }

Nesting the properties, this becomes:

body
{ 
    … 
    font: 
    {
        size: 75%;
        family: Verdana, Tahoma, Arial, "Helvetica Neue", Helvetica, Sans-Serif;
    }
    … 
}

Breaking up the SCSS File

Nesting the css goes some way to adding some logical structure to the file, but the file itself is long. We probably do not want multiple css files as this puts more work the server and decreases page load /render times. SASS allows us to break the scss file through use of the @import directive. We can import plain css files or .scss this way, performance a live server is unaffected as the result is still our sinlge css file if we set up correctly.  We can break scss file down into multiple separate ones, the obvious places to refactor are where Microsoft added a comment as a heading (e.g. for the menu to separate the menu styling in the file).  I will do this in the sample application, but it would be unwieldy to show this in the article, so see the solution for what I did.  I want to make one further additional .scss file for common declarations which I will use as the example here. Remember the parameters and rounded corner mixin we created earlier in this article? 

$base-color: #FFA0A0; //Define a pink base color
$base-text-size: 1em;

I also know that I am going to add further features to this file later in the article, so I want to separate these out into a file called "CommonDeclarations.scss" As workbench is installed this is easy, right click the "Content" folder Visual Studio’s solution explorer and select "Add a new item". Under “Web” (I had to scroll YMMV) you will find this 

 Change the name to “_CommonDeclarations.scss” and click add, the underscore prefix by convention, telling SASS the file is for import (a Partial File). Next I just cut the things I want in this file from the old and paste into the new.  The final step is to add the line @import "CommonDeclarations";  to the. scss files where things defined common declarations are used Note that I do not need the file extension or the _ prefix.  Now I can continue to break down the main site.scss file in the same way. I will create a file for each comment acting as a section header  in the original css added by Microsoft when the project was created as an example as each of these tend to deal with one logical grouping.

Other Directives

As stated earlier, the @ prefix denotes a directive, there are other s built in that allow us to increase our DRY creamy goodness. I will visit these in turn

The @extend Directive

This allows us to derive on style based on another. The css that deals with the validation elements on any web-forms is a good example. After the refactoring into separate style sheets, this currently sits in the _ValidationHelpers.scss file:

.field-validation-error 
{ 
    color: #ff0000; 
} 

.validation-summary-errors
{ 
    color: #ff0000; 
    font-weight:bold;
} 

Both these items are in red, it is likely if we want to change the colour we will want to change both. We could use a parameter in this basic example, but there is also arguably a genuine relationship here, the summary style  relates  to the field validation, so I will remove the colour on the summary style and extend the field validation style: 

.field-validation-error
{
    color: #ff0000;
}

.validation-summary-errors
{
    @extend .field-validation-error;
    font-weight: bold;
}

I only need to do this if there is a true reliance of one style on another, the litmus test of this is that if we want the base style to change, should the extended one.  One thing to note is that the css generated is slightly different now: 

.field-validation-error,
.field-validation-error, .validation-summary-errors {
  color: #ff0000; }
.validation-summary-errors {
  font-weight: bold; }

Note that the css has been part-minified, this is something else that SASS can provide, though we do not cover it in this article. It is possible to extend from extended styles (called chaining) and to use multiple extends in the same block, though none of the project css is complicated enough to warrant this. It is also possible to extend complex selectors, such as a:hover, the syntax is just the same. More documentation on extend can be found here  

Other Directives – Functions and Control Flow

For completeness we will cover some of the more advanced fundamentals. 

Functions

SASS Has built-in functions, for example the function hsl  takes three arguments hue, saturation and lightness and converts it to RGB:

As an example, we shall set the H1 used in the main layout to a mid-purple colour using the hsl function.

#header h1
{
    …
    color: hsl(308, 44%, 28%);
    …
}
This compiles to  
#header h1 {
  …
  color: #67285e;
   …
}

The documentation recommends using explicit keyword arguments, whilst meaning the same thing as above, it suggests the following in the interests of clarity:

#header h1 {
  …
color: hsl($hue: 308, $saturation: 44%, $lightness: 28%);
   …
}

Whichever syntax you use, the results ins the rather fetching design Smile | <img src=

 

Extending the Available Functions

We can extend the list of functions to add our own. Let's suppose we want to standardise our widths to be multiples of 10px. We could provide a function to do this:

$base-width: 10px; 
@function keith-width-multiplier($multiple) 
{ 
  @return $multiple * $base-width; 
}

Note that I have prefixed the function name with keith, the SASS documentation suggest that you prefix all  custom functions with something to distinguish them from the pre-existing ones such as hsl. It suggests using your company name, but as I am working in my own time I have decided to show great humility and use my own name Smile | <img src=

Now, to take a hypothetical example:  

.foo
{
  width: keith-width-multiplier(3);
}

This would result in everything with class foo having a width of 30px.

Control Flow Directives

These are considered an advanced feature in SASS, even the documentation suggests you should not use these normally: http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#control_directives.  I have included them as with these, the SASS syntax is functionally complete. Like the custom function above, I have not included the examples below in the sample code, they are simply not needed. The examples that follow may also not be the best way to achieve what is needed (they are not included in the sample code), they are intended to be as clear as possible rather than real-world.

@if  

As we would expect , this allow a decision. Let’s suppose we want to set the colour of a span according to a variable $backgroundcolor. If the is white, color should be black, if is $backgroundcolor black color should be white, otherwise color should be gray.

span 
{ 
  @if $backgroundcolor = #FFFFFF
  {
    color:#000000;
  }
  @elseif $backgroundcolor = #000000
  {
    color:#FFFFFF;
  }
  @else
  {
    color:#696969;
  }
}

Naturally, the above would benefit from some refactoring in a real situation!

@for and String Interpolation #{…}

This is our first looping construct, it loops between values. With this we can even create multiple css definitions. In this example we will create styles for headings h1 through to h4, with diminishing font-sizes:   

$biggest-width: 8em; 
@for $i from 1 through 4
{ 
    h#{$i} {
        font-size:  $biggest-width /$i;}
}
When compiled this generates h1:
h1  { 
  font-size: 8em; }  
h2 { 
  font-size: 4em; } 
h3 {
  font-size: 2.667em; }
h4 {
  font-size: 2em; }
}

Note the term #{$i}, this takes the value (in thise case $i) and outputs it directly into the css. Not only can it be used in loops, it can be used for property names and values too. Another thing to not that for the four heading types this loop is overkill. If you can imagine setting up several table column or row styles, the looping construct makes more sense.

@while 

While performs a similar function to the for loop. Like any while loop in a mainstream language, the value must change in the loop so the condition terminates.  We can re-write the for loop above as :

$val : 1;
@while $val = 4 {
  h#{$val} {
font-size:  $biggest-width  / $val<}
}

This outputs the same css as the for loop, but is less elegant in this case: just because you can, it doesn’t mean you should Smile | <img src=. In a real situation, the while loop might be used for more complex looping.

@each  

Each iterates over a list, the list can be anything. For simplicity I’d like to use the example of creating a  .red class style that has red text, a black one and a green one:

@each $color in red black green <{
  .#{$color&} { color:  $color;}
}

This outputs:

.red { 
  color: red}
.black {
  color: black;} 
.green { 
  color: green; }

In this case we have assigned a variable $color  to a value in a list of strings

Conclusion

When I started web-devving many years ago I was frustrated coming from a [then] predominately c++ background. Why did I need to keep repeating the values in the colour palette? Why couldn’t I base the colour of one style on that of another or a palette value? Why does the  css syntax not reflect the nesting of the selectors well? All these problems are answered more-or-less by SASS:

  • Parameters
  • Functions and mixins
  • The nesting sytax

Additionally SASS allows us to define our own functions, allowing for extension points. It also allows us to break down our .css into logical file blocks without compromising on performance. Finally SASS allows us  add control flow to our CSS, pretty much making it Turing complete.

SASS (or SASS-like technologies) are almost a no-brainer assuming you have an environment that allows you to use it and that bar is pretty low. It allows you to simplify and rationalise your css to a degree you are happy with, inducing little to no real cost.

Revision History

  1. 24/07/2012 Initial Version. 
  2. 25/07/2012 Added Missing Sample solution! 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Keith Barrow
Software Developer (Senior)
United Kingdom United Kingdom
I Graduated in Natural Sciences (Chemistry & Physics) from Durham University, where I did not cover myself with glory, but did fill, and often cover, myself with beer.
 
I qualified as a secondary school teacher, but I hated teaching. I worked as an IT techhie for a few years but kept being promoted to IT Trainer, thanks to my teaching experience, which I also disliked. I spent some time working out what else I could do instead and reduced beer intake.
 
I realised that I should work as a programmer, having enjoyed it a hobby since I was a nipper in the halcyon days of the Sinclair Spectrum (48k, Rubber Keyboard). Spent two weeks working out why I didn't think of this to start with, instead of starting my dull-as-ditch-water Chemistry degree 8 years earlier. Had a beer to celebrate.
 
I Graduated in 2001 with an MSc from Newcastle Uni in Comp Sci. Did cover myself with glory, and drank some beer.
 
.Netting ever since, and loving it. Though I have largely given up beer due to not being able to hack the pace like I used to.
 
I was born, brought up, and have lived most of my life near Newcastle. In a fit of temporary insanity I moved to Amman, in my wife's homeland of Jordan, but made it back safely to the UK without any extra holes being made in my person by bullets. To be fair it was pretty safe at the time, if you ignored the roads.
 
Visit Jordan if you can by the way, the landscape is beautiful and varied, the food excellent and the people the friendliest on earth, after Geordies naturally Smile | :) .
Follow on   Twitter   Google+

Comments and Discussions

 
GeneralIt seems the formatting has gone wrong.[Edit] [modified] PinmentorKeith Barrow25-Jul-12 1:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141220.1 | Last Updated 25 Jul 2012
Article Copyright 2012 by Keith Barrow
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid