Sass (Syntactically Awesome Style Sheets) tries to make CSS fun again.
It's a set of "extensions" on top of standard CSS that make it easier to write and maintain style sheets.
A Sass file compiles down to regular CSS so it doesn't require any special browser plug-ins.
This article is aimed at Microsoft developers but the Sass language sections apply to anyone wanting to get an overview of Sass, regardless of the web programming platform or IDE you're using.
Sass Tooling Options
One of the easiest ways to get some Sass goodness into you ASP.NET app is to use Mindscape's Web Workbench. This Visual Studio extension provides Sass editing and compilation support (in addition to LESS and CoffeeScript support). The basic version is free :)
For other ways of getting Sass into your workflow checkout the resources section at the end of this article
Installing Web Workbench
Install the Web Workbench Visual Studio extension - at the time of writing there is support for VS2010 and VS2012.
Once you've installed, you'll find some new items that you can add to your ASP.NET applications.
Getting Started with Sass in an ASP.NET Web Forms Project
- In Visual Studio, create a new ASP.NET Empty Web Application
- Add a new Web Form item called default.aspx
- In the header, add
<link href="css/styles.css" rel="stylesheet" />
- Create the "css" folder
- In the css folder, add a new item, choose "Sass SCSS Style Sheet" and name it "styles.scss". This will create and open a .scss file with the default content of
body {}
- Edit the file so it reads:
body {background-color: black;}
- Save the file, and wait a few seconds...
- If you now look in solution explorer you'll see a styles.css file has been generated by Web Workbench (you might have to expand the "styles.scss" to drill down into it)
- Run the app and you'll see that the background has been changed to black.
- Every time you make a change and save styles.scss, styles.css will be re-created.
The same process is used when working in a ASP.NET MVC application.
The remainder of this article focuses on Sass language features, you can experiment with all of these in your newly created web app :)
Basic Sass Language Features
Variables
Sass variables are like variables in a regular programming language. You can use them as simple constants to represent colours, sizes, etc. Variables can also be manipulated using basic mathematical operators.
The following Sass defines 3 variables: baseFontSize with a value of 16; bgColor with a value of #FFF; and defaultTextColor with an RGB colour.
$baseFontSize: 16px;
$bgColor: #FFF;
$defaultTextColour: rgb(255,25,233);
Once we have defined variables we can use them in our CSS rules.
We can create a CSS rule for all body text, and one for <h1>
headers that will be 3 times the size of the body text:
body {
font-size: $baseFontSize;
}
h1 {
font-size: $baseFontSize * 3;
}
This will generate the following CSS:
body {
font-size: 16px; }
h1 {
font-size: 48px; }
Notice how the px suffix has been automatically added to the calculated <h1>
.
If we wanted to divide a container into two parts using fixed pixels, we can define a variable to represent the width of the 1st element and then use Sass to work out the remaining:
$containerWidth: 1000px;
$firstColumnWidth: 300px;
$secondColumnWidth: $containerWidth - $firstColumnWidth;
#container {
width: $containerWidth;
}
#columnOne {
width: $firstColumnWidth;
}
#columnTwo {
width: $secondColumnWidth;
}
This will generate:
#container {
width: 1000px; }
#columnOne {
width: 300px; }
#columnTwo {
width: 700px; }
Mixins
Mixins allow you to apply a set of properties to one or more CSS rules. The content gets "mixed in" to the rest of the CSS rule.
You define a mixin by using: @mixin followed by a unique name for it:
@mixin visually-hidden {
visibility: hidden;
display: none;
}
#validationErrorMessage {
color: red;
@include visually-hidden;
}
This will generate:
#validationErrorMessage {
color: red;
visibility: hidden;
display: none; }
Notice how the CSS has been added to what was already there (the color: red;
).
We can also include more than one mixin:
@mixin big{
font-size: 1000px;
}
@mixin red{
color: red;
}
#bigAndRed {
@include big;
@include red;
}
This generates:
#bigAndRed {
font-size: 1000px;
color: red; }
Later in this article we'll take a look at mixins with arguments which are even more awesome.
Nesting
This is potentially one of the more confusing Sass features when you first see it.
Simple Nesting
The first way of using nesting is to reduce the repetition of typing (and future changing) of rules that begin with the same thing.
For example, say your navigation consists of <a>
contained in an <ul>
contained in a <div>
called "mainNavMenu". You might hand-type the following CSS:
#mainNavMenu {
width: 100%;
height: 50px;
}
#mainNavMenu ul {
list-style-type: none;
}
#mainNavMenu li {
float: left;
}
#mainNavMenu li a {
font-size: 20px;
}
You just typed "#mainNavMenu" 4 times, which is not a big deal but if you want to change the name that's another 4 changes. Also note that there is an implied "nesting": they all come under "#mainNavMenu". We can use Sass nesting to reduce the overhead and simplify the declaration:
#mainNavMenu {
width: 100%;
height: 50px;
ul { list-style-type: none; }
li {
float: left;
a { font-size: 20px; }
}
}
Now if we need to change the name we only have to do it once and the generated CSS will be updated.
This results in the following CSS:
#mainNavMenu {
width: 100%;
height: 50px; }
#mainNavMenu ul {
list-style-type: none; }
#mainNavMenu li {
float: left; }
#mainNavMenu li a {
font-size: 20px; }
Property Nesting
It's also possible to nest properties. This feature of Sass is like a shortcut so you don't have to retype property and nested property prefixes such as border-bottom-
.
For example, say we wanted a box with a solid border that has a 100px blue top line and a 200px red bottom line. Using Sass property nesting we can write:
.awesomeBox {
border: {
style: solid;
top: {
width: 100px;
color: blue;
}
bottom: {
width: 200px;
color: red;
}
}
}
Which will generate the following CSS:
.awesomeBox {
border-style: solid;
border-top-width: 100px;
border-top-color: blue;
border-bottom-width: 200px;
border-bottom-color: red; }
It's interesting in this example that there are more lines in the Sass definition than are generated. I'm not sure that the Sass version is actually more readable or not, but for a larger number of nested properties this feature might be worth using.
Advanced Sass Features
The previous section introduced some basic Sass concepts. This section expands on these ideas and introduces some more powerful features.
Mixins with Parameters
Mixins can take a comma delimited list of parameters. For example, if we are using some custom fonts and importing them using @font-face
we can write a parameterised mixin:
@mixin fontFace($fontFamily, $fontFileName, $fontWeight: normal, $fontStyle: normal )
{
@font-face {
font-family: $fontFamily;
src: url('#{$fontFileName}-webfont.eot');
src: url('#{$fontFileName}-webfont.eot?#iefix') format('embedded-opentype'),
url('#{$fontFileName}-webfont.woff') format('woff'),
url('#{$fontFileName}-webfont.ttf') format('truetype');
font-weight: $fontWeight;
font-style: $fontStyle;
}
}
There are several things going on here. Firstly we define two mandatory parameters $fontFamily
and $fontFileName
. We also define two optional parameters $fontWeight
and $fontStyle
, that both have default values of normal
if they are not explicitly specified when the mixin is called.
Within the mixin we create a @font-face
rule that defines a font-family and then a list of font files of different font formats. The url to these font files is composed of the value of the $fontFileName
parameter value, plus a suffix to the different font files.
To use this mixin to reference two hypothetical fonts: "AwesomeFont1" and "AwesomeFont2" that both exist in the directory "myfonts" we would write:
@include fontFace("AwesomeFont1", "myfonts/AF1");
@include fontFace("AwesomeFont2", "myfonts/AF2", bold, italic);
This would generate:
@font-face {
font-family: "AwesomeFont1";
src: url("myfonts/AF1-webfont.eot");
src: url("myfonts/AF1-webfont.eot?#iefix") format("embedded-opentype"), url("myfonts/AF1-webfont.woff") format("woff"), url("myfonts/AF1-webfont.ttf") format("truetype");
font-weight: normal;
font-style: normal; }
@font-face {
font-family: "AwesomeFont2";
src: url("myfonts/AF2-webfont.eot");
src: url("myfonts/AF2-webfont.eot?#iefix") format("embedded-opentype"), url("myfonts/AF2-webfont.woff") format("woff"), url("myfonts/AF2-webfont.ttf") format("truetype");
font-weight: bold;
font-style: italic; }
Referencing a Parent Selector
If you have nested rules, the "&" can be used to allow you to insert the parent selector into the nested rule.
For example, to add :hover
and :visited
states to a link:
a {
font-size: 100px;
&:hover { font-size: 200px; }
&:visited { text-decoration: underline; }
}
This generates:
a {
font-size: 100px; }
a:hover {
font-size: 200px; }
a:visited {
text-decoration: underline; }
Note the "&" has been replaced with the parent selector, in this example the a
.
Comments
To add comments to your Sass (.scss) file that you don't want outputting to the generated CSS use the single line comment style:
// this won't be in generated CSS
// nor this
To have comments make it into the generated CSS, use multiple line comment style:
/* This
will
all
be
output */
Importing Other Sass (.scss) Files
You don't have to put all your Sass stuff in one file, you can instead import other .scss files into a main file.
For example, you could put all variables in a "base.scss" file and use them in a "main.scss" file by adding @import "base.scss";
to the top of the file. You would then just reference main.css in your HTML.
Loops
You can iterate and use the value of the iteration "counter" to create multiple CSS rules.
For example, to set the size of headings, with each heading level being 10px smaller than the last, with h1
starting at 100px:
$sizeDifferenceBetweenHeadings: 10px;
$biggestHeadingSize: 100px;
$currentHeadingSize: $biggestHeadingSize;
@for $i from 1 through 6 {
h#{$i} { width: $currentHeadingSize }
$currentHeadingSize: $currentHeadingSize - $sizeDifferenceBetweenHeadings;
}
This generates:
h1 {
width: 100px; }
h2 {
width: 90px; }
h3 {
width: 80px; }
h4 {
width: 70px; }
h5 {
width: 60px; }
h6 {
width: 50px; }
You can also use @each
to enumerate a comma separated list of things, and @while
to do conditional-based loops.
Inheriting from Another Style
If you have a style that should have all the properties of an existing one, but with some additional properties you can use the @extend
directive. You could think of this like inheritance for styles.
For example, if we had 3 types of message such as information, warning and error; error and warning "inherit" from information.
.information {
font-size: 10pt;
color: black;
border-width: 10px;
}
.warning {
@extend .information;
color: orange;
}
.error {
@extend .information;
color: red;
}
This generates:
.information, .warning, .error {
font-size: 10pt;
color: black;
border-width: 10px; }
.warning {
color: orange; }
.error {
color: red; }
.information
You could also have a chain of "inheritance": criticalError extends error extends warning extends information.
Adding Debug and Warning Messages to Sass Compilation
You can add messages to be output during CSS compilation by using the @debug
and @warn
directives.
Depending on what Sass compiler tool you're using, they will be manifested in different ways. In Visual Studio with Web Workbench you can see debug and warning messages in the Output window (you'll need to select "Web Workbench Output" in the drop down).
The following 2 lines:
@debug 10em + 12em;
@warn "stupid";
Will result in the following in the output window
"C:\WebApplication1\WebApplication1\Scss1.scss:185 DEBUG: 22em
WARNING: stupid on line 186 of C:\WebApplication1\WebApplication1\Scss1.scss"
Responsive Web Design using Sass
Responsive web design is the hiding, showing or reformatting of HTML elements based on the capabilities of the device - usually screen width. For example, on a mobile device some columns or headers may be hidden, whereas on a desktop with a bigger screen they would be shown.
For example, to control the size of a header logo based on screen width:
$breakpointSmallScreen: 320px;
$breakpointMediumScreen: 700px;
$breakpointLargeScreen: 1200px;
.headerLogo {
float: left;
width: 100px;
@media screen and (min-width: $breakpointSmallScreen) {
width: 200px;
}
@media screen and (min-width: $breakpointMediumScreen) {
width: 300px;
}
@media screen and (min-width: $breakpointLargeScreen) {
width: 400px;
float: right;
}
}
Notice the use of variables to define the responsive breakpoints, this generates:
.headerLogo {
float: left;
width: 100px; }
@media screen and (min-width: 320px) {
.headerLogo {
width: 200px; } }
@media screen and (min-width: 700px) {
.headerLogo {
width: 300px; } }
@media screen and (min-width: 1200px) {
.headerLogo {
width: 400px;
float: right; } }
For an awesome post on Sass and responsive design see: Responsive Web Design in Sass.
Colour Functions
There are a number of useful Sass functions for working with colours such as lightening and darkening, check out the full list.
It's entirely possible to create a complete colour scheme for a web site using a single base colour variable and then using Sass colour functions.
A crude example:
$baseSiteColour: #0000FF;
$pageBackgroundColour: lighten(desaturate($baseSiteColour, 30%), 40%);
$standardTextColour: darken($baseSiteColour, 30%);
html {
background-color: $pageBackgroundColour;
}
h1 {
color: $baseSiteColour;
}
p {
color: $standardTextColour;
}
Generates:
html {
background-color: #d4d4f7; }
h1 {
color: blue; }
p {
color: #000066; }
Now simply by changing the value of $baseSiteColour
, the whole colour scheme of the site will change.
Conclusion
I used Sass to do all the CSS work on my recent blog redesign and I intend to use it on all new projects.
I'm unsure exactly how I would introduce Sass into an existing application, you could simply rename your .css file to a .scss file and slowly start to introduce some Sass goodness over time; perhaps start by replacing repeated colours with Sass variables.
Mixins (especially parameterised ones) and variables are the most understandable features to get started with and start to reduce maintenance overheads.
Because we can import one .scss file into another, I have seen some authors who have a commonstuff.scss that they use on all projects. This common file is like a Sass library of general-use mixins, etc.
There are more features in Sass, check out the full reference for a complete breakdown.
Resources
Other tooling options instead of Web Workbench:
Further reading:
SHARE: