Getting SASSy with CSS






4.89/5 (11 votes)
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
.
Through all this, I’m repeating (at least) ul#menu li#greeting
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
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
.
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
.
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
- 24/07/2012 Initial Version.
- 25/07/2012 Added Missing Sample solution!