SASS Tutorial
If you’ve already created a website, you’re probably familiar with CSS. However, you might also have missed some hidden features when working with the stylesheet language. Designing websites with CSS can be very tedious, which is why so many developers now rely on SASS. Behind the acronym is a promise: syntactically awesome stylesheets. SASS is both a preprocessor and a stylesheet language.
The fact that this is a preprocessor is because it needs to be converted. Before SASS can be played, the source code needs to be compiled into ordinary CSS. We also explain how this step works in the detailed SASS tutorial. To simplify learning SASS, we’ll take you step by step and explain everything with examples.
You’ll find more information in our overview article more information on SASS.
SASS requirements
SASS is, in principle, platform independent, which means you can work with it on PC, Mac, or Linux. SASS is based on Ruby, at least in the original version. Therefore, you need to have the programming language integrated into your system. Ruby should be pre-installed in macOS. For Windows PCs you can use the RubyInstaller. The installation package contains the language, a development environment (which you don’t need for SASS), and documentation. Installation is also easy for Linux users.
There are also practical installation packages for other systems. A list can be found on the official Ruby website.
The LibSASS project also bring SASS to other programming languages: C/C++, Java, JavaScript, Node PHP, Python, and a few other languages are available. Using appropriate wrappers (an implementation tool) you can take advantage of other programming languages. LibSASS, which is designed for libraries, as well as information about available wrappers, can be found on the official project website.
Installing SASS
There are several ways to install SASS in your system. In the meantime, several applications have been established to make your work with the stylesheet language easier. Some of these fees are free, but some (like Koala or Scout App) are available free of charge as open source software. In principle, however, you don’t need any additional programs to use SASS on your system. Ruby contains the package manager gem, with which the stylesheet language can be easily implemented using a command line command. To do this, open the terminal or the command prompt and enter the following command:
gem install sass
This should be enough. If you receive an error message, you might not have the necessary installation rights. You can fix this by working with the sudo command (macOS, Linux) or starting the command prompt as an administrator using the right mouse button (Windows). To check whether the installation was successful and up to date, ask SASS which version is installed:
sass -v
In addition to the installation, you should also set up the compilation. In order for your SASS code to work on a website, it must first be converted to CSS. There are several ways to do this: if you have chosen one of the programs to install SASS, you can also use it for compilation. If you work with the task runners Grunt or Gulp, they will do the work for you once you have set them up. For some text editors, there are even plugins that do the compilation for you. However, you can also do the conversion step from the command line.
SASS gives users the option to either recompile after each change in the source code or to enable a monitoring mode. In the latter case, the compiler checks either a file or an entire folder and performs the conversion automatically. To monitor, use the command line to navigate to your website’s folder and start one of the two commands:
sass --watch example.sass:example.css
You can monitor the file “example.sass” and compile the source code into the file “example.sass.” If you add two more subfolders in your project folder – one for SASS files and another for CSS files – then name them “sass” and “css” files accordingly, and you can monitor the entire folder:
sass --watch sass:css
As soon as you make a change in the SASS files and save them, the compiler automatically overwrites the existing CSS files with the newer versions.
You may want to move your existing website, already written in traditional CSS, to SASS. You will also need to convert your old CSS code. Before you do this, however, you should consider whether you want to work in the original SASS syntax (in short: SASS) or choose the newer SCSS variant. You can read more about the difference between SASS and SCSS in our basics article. There are also commands for the conversions:
sass-convert example.css example.sass
sass-convert example.css example.scss
The converter reads the corresponding formats from the file extensions. Alternatively, you can use a useful, simple website: for CSS 2 SASS/SCSS converters, enter your CSS code on the left side of the window and display the converted source code on the right side in the desired format. Now you just have to copy the code into a file. If you decide to use SCSS, the conversion is optimal: rename your files – instead of “.css,” just type “.scss.” Any code written with CSS rules also works under SCSS.
SASS: the stylesheet language’s syntax
As previously mentioned, there is more than one syntax when it comes to SASS. Two competing formats have established themselves. Originally, SASS was based on the syntax now known as “indented syntax,” where indentations trigger nesting and a line break effectively terminates a line of code. SCSS, on the other hand, is more oriented towards the CSS format and requires curly brackets and semicolons. To get this tutorial to work regardless of the syntax, we will present the procedure in both formats. Here is a step-by-step guide to the peculiarities of SASS.
If you just want to test out the stylesheet language, you can do so in your browser. Using the Sass.js Playground or SassMeister, enter your code online and directly create the corresponding source code in CSS.
Variables
Most web developers appreciate the use of variables in SASS. With this useful function, you can save information under an alias and reuse it wherever you want. Variables are very popular in terms of colour and size specifications, for example. A variable can be used to store a color’s hex value, or to adjust a fixed size using mathematical functions. Variables are introduced in SASS with a dollar sign ($):
SASS
$bg-color: #df0174
$size: 1em
SCSS
$bg-color: #df0174;
$size: 1em;
Then you just have to insert the variables at the appropriate places in the code:
SASS
$bg-color: #df0174
$size: 1em
body
background-color: $bg-color
margin: $size * 2
SCSS
$bg-color: #df0174;
$size: 1em;
body {
background-color: $bg-color;
margin: $size * 2;
}
When compiling, the compiler finally adapts the syntax to CSS again and resolves the variables:
CSS
body {
background-color: #df0174;
margin: 2em;
}
When naming colour values in the form of variables, two different principles are established. Some developers find it convenient to name the colour directly ($pink), others prefer to specify its purpose ($bg-color). In principle, however, you can freely choose the name of the variables.
It may be useful to specify a default value for certain variables. Unless otherwise defined, SASS assumes this information. Conversely, if you define the variable differently, the default information is ignored. This can be useful, for example, if a developer passes an incomplete product onto a client who still wants to make changes, or if a web designer uses his own template. You can create a preset like this by setting a “!default” flag. You can enter both normal values and variables that have already been defined:
SASS
$text-color: #000000 !default
$background-color: $bg-color !default
SCSS
$text-color: #000000 !default;
$background-color: $bg-color !default;
Importing
SASS has a handy directive that allows you to include other files in the stylesheet. For example, you create a file where you define all variables (here you can specify and name all required colour values) and then import the file. Now use the information from the imported file as if it were in the current source code. This helps you keep your stylesheets clear. You can import as many files as your like using “@import” – even for subdirectories. The function even handles importing multiple files in one step:
SASS
@import "variables"
@import "partials/styles"
@import "partials/test-a", "partials/test-b"
SCSS
@import "variables";
@import "partials/styles";
@import "partials/test-a", "partials/test-b";
If you want to include .sass. or .scss files, you don’t need to specify a file extension; the system automatically assumes that you mean these files types. You can also include CSS files. However, you also specify the extension so that the computer knows exactly what you mean. Compiling also resolves this simplification: the final CSS code no longer contains the directive, just the information from the corresponding files.
Partials
Partials are the most common thing you’ll import when working with SASS. Partials are code fragments, and they allow you to create modules that you can easily install again and again. If you name the file, it’s important to place an underscore before the actual name. This informs the compiler that the corresponding file does not require a CSS counterpart. Otherwise, the system would convert all SASS files to CSS if properly monitored.
If you import the partials, omit the underscore. SASS also knows which file you mean. Therefore, it is necessary that you don’t create files with the same name. If you have both “example.sass” and “_example.sass,” this will lead to an error. This also applies to the file extensions: “example.sass” and “example.scss” shouldn’t be in the same directory.
Mixins
Another important directive are mixins. These are fixed rules that you can call up again and again in the stylesheet without having to insert the complete code again. This helps to work faster and keep the code leaner. Everything that is allowed in SASS can be included in a mixin – rules, parameters, or functions. Even if space in the mixin has no restrictions, it should not contain more than twenty lines. The ultimate goal is to increase simplicity instead of just making everything more complicated.
To handle mixins effectively, you need two directives: “@mixin” and “@include.” With the first one, you create the template, with the second you include the code block:
SASS
@mixin big-blue-text
font-family: Arial
font-size: 25px
font-weight: bold
color:#0000ff
SCSS
@mixin big-blue-text {
font-family: Arial;
font-size: 25px;
font-weight: bold;
color:#0000ff;
}
}
When creating the mix, give the template a name (e.g. hidden). With this, you can also re-integrate the code block at the chosen positions:
SASS
@include big-blue-text
SCSS
@include big-blue-text;
In the final CSS code, the complete source code block appears instead of the mixin. The definition of the mixin itself (@mixin) does not appear there anymore.
Extend
The extend rule saves you a lot of work. This directive ensures that all properties in one class are passed to another. To avoid redefining everything, use “@extend.” The directive also works as a chain. A class defined by “@extend” can be part of a third class:
SASS
.button-scope
margin: 5px
border-radius: 2px
.home-button
@extend .button-scope
background-color: $black
.back-button
@extend .home-button
SCSS
.button-scope {
margin: 5px;
border-radius: 2px;
}
.home-button {
@extend .button-scope;
background-color: $black;
}
.back-button {
@extend .home-button;
}
The compiler resolves the code as follows:
CSS
.button-scope, .home-button, .back-button {
margin: 5px;
border-radius: 2px;
}
.home-button, .back-button {
background-color: #000000;
}
In some situations, you define the appearance of a category that you don’t want to use on your actual website, using the form @extend. This happens frequently when you are building your own library. SASS offers placeholder selectors for these situations. You use a percentage sign (%) to identify a class that you only create to use in other classes. If you don’t import this kind of selector when designing your website, SASS will not compile it into CSS:
SASS
%module
margin: 20px
padding: 10px
color: $bg-color
.post
@extend %module
color: $grey
SCSS
%module {
margin: 20px;
padding: 10px;
color: $bg-color;
}
.post {
@extend %module;
color: $grey;
}
In the final CSS code, the class “module” no longer appears. Their properties are passed directly to the class “post.”
CSS
.post {
margin: 20px;
padding: 10px;
color: …;
}
.post {
color: #D3D3D3;
}
The “!optional” flag can also be very helpful for extend – if you write an extension for a class that doesn’t exist, SASS will generate an error during compilation. With !optional you can avoid this. SASS will just ignore the command if it doesn’t find a suitable class.
The effects of mixins and “@extend” are very similar, and in most cases, it makes sense to use mixins. A detailed article about the differences can be found on csswizardry.com.
Nesting
In HTML, it goes without saying that the code is divided into a hierarchical tree structure. CSS ignores this function and forces the user to declare properties over and over again. SASS brings the possibility of nesting back into the stylesheets by allowing subcategories to inherit the properties of the parent category. This also ensures that the code remains slimmer overall and the work involved in writing and waiting is less. For example, it is possible to define the appearance of links and determine within the nesting how these links look when hovering – or if they have already been visited.
If nesting is used in the code, the ampersand (&) is used to replace part of the selector with the parent.
SASS
a
color: $blue
&:visited
color: $red
&:hover
color: $purple
SCSS
a {
color: $blue;
&:visited {
color: $red;
}
&:hover {
color: $purple;
}
}
During compilation, the nesting must be resolved again. In CSS, each state reappears separately defined.
CSS
a {
color: #0000FF;
}
a:visited {
color: #FF0000;
}
a:hover {
color: #551A8B;
}
Besides the nesting resolution, the compilation also ensures that the variables (the definition of which we omitted in the example) become hex values again.
Nesting is a very helpful tool to keep the stylesheet’s source code lean and efficient. However, there is a tendency to overexploit this nesting possibility, so reversing the actual effect and creating a complicated structuring system. This can cause problems, especially with modifications and maintenance. For this reason, you should refrain from subdivisions from the third level onwards.
With nesting, you can also pass on “properties.” CSS knows some characteristics that belong to the same family. For example, all font formatting information belongs to the same family, but needs to be defined in CSS as individual points – with their complete property names. SASS gives you the opportunity to group the individual properties under the family names.
SASS
.example
font:
family: serif
style: normal
size: medium
SCSS
.example {
font: {
family: serif;
style: normal;
size: medium;
}
}
Functions
SASS has numerous functions to make working with your stylesheet easier. These are prefabricated workflows that you would otherwise have to perform manually. The functions can be assigned to different categories:
- Colours: With these functions, you can adjust color values, saturation, transparency, and many other properties. For example, you can mix a new color with mix() from two colors.
- Listen: For lists (series of CSS property values), you can use functions to read the number of entries, for example, or merge several lists into one.
- Strings: Strings are fixed strings, like those used in texts. Functions of this kind automatically put a string in quotation marks of a complete text in uppercase letters.
- Selectors: With this category of functions, you can manipulate complete selectors. For example, “selector unify()” allows you to make one out of two selectors. This may save you a lot of paperwork.
- Numbers: In the area of numbers, values, or units, you will find functions that can, for example, round up and down, find the largest number in a set, or display a random number.
- Maps: In SASS, maps are data structures consisting of keys and properties. The corresponding functions manipulate the collections. For example, you can merge two maps or delete a specific key from a map.
- Introspection: Functions from this area provide insight into the complete stylesheet’s content. For example, check whether a specific feature, mixin, or function exists in your code.
- Miscellaneous: Miscellaneous SASS includes the helpful “if()” function. This should not be confused with the directive of the same name. The difference is explained in the section “branching” below.
A complete list of SASS functions that are already included in the installation package can be found in the stylesheet language’s official documentation. You will be able to find a short explanation of each function there.
You always insert functions into your code according to the same pattern: each function has an individual name and contains certain parameters in brackets, separated by commas. At the end, the function outputs a single value. Using a simple but very useful mix() function as an example, we will explain the SASS syntax:
SASS
$color-1: #ffff00
$color-2: #0000ff
body
background-color: mix($color-1, $color-2, 30%)
SCSS
$color-1: #ffff00;
$color-2: #0000ff;
body {
background-color: mix($color-1, $color-2, 30%);
}
With this function, mix the two color values that you’ve already defined as variables (colour values don’t need to be saved as variables; you can place the hex values directly in the function). The third parameter is what the mixing ratio should be: in our example, 30% of “$color-1” is included in the final result. If you leave the last parameter empty, SASS assumes a 50/50 mix. Just one value appears in the CSS itself – the resulting color’s hex value:
CSS
body {
background-color: #4d4db3;
}
All the functions mentioned so far are already in SASS’s delivery state. The stylesheet language also allows you to define your own functions for a project. This makes it easier and faster to carry out work steps that occur frequently. This means that functions are similar to mixins. Whilst the latter have lines of code as output, functions only return one value. They create functions with the corresponding “@function” directive. In fact, you always create a function with a pair of directives. In addition to the “@function,” an integrated “@return” is required where you define the output value:
SASS
$column-count: 12
@function column-width($num)
@return $num * 100% / $column-count
.three-columns
width: column-width(3)
SCSS
$column-count: 12;
@function column-width($num) {
@return $num * 100% / $column-count;
}
.three-columns {
width: column-width(3);
You can use the exemplary function to perform a calculation for column width for a layout grid. In this example, there are 12 columns. In the next step, name the function and define how many parameters it contains – in this example, it’s a number. Furthermore, we determine what the function should do and therefore also what value it outputs. In this case, “column-width” multiplies the number you enter as a parameter by 100% and divides the result by the number of columns. Once you have defined the function, you can use it again and again with changing parameters. Only the resulting value is stored in the final CSS:
CSS
.three-columns {
width: 25%;
}
You can use either bind or underscore characters in the name when creating functions. IF you call the function later, the distinction does not matter. Both “function-name” and “function_name” call the same function.
Loops
Loops give the stylesheet language the appeal of a real programming language. Use Loops to create statement blocks in SASS that are repeated until a condition you specify occurs. There are three different directives available for creating loops:
- @for
- @while
- @each
The “@for” loop is the standard case of a loop in the context of programming. The loop starts at the start and repeats the job until an exit state, and the end is reached. In SASS, this directive comes in two different variants: Either the last cycle is run again when the target is reached or the loop is exited beforehand.
SASS
@for $i from 1 through 4
.width-#{$i}
width: 10em + $i
@for $i from 1 to 4
.height-#{$i}
height: 25em * $i
SCSS
@for $i from 1 through 4 {
.width-#{$i} { width: 10em + $i; }
}
@for $i from 1 to 4 {
.height-#{$i} { height: 25em * $i; }
}
After the directive, you first specify any variable ($i) and then define the start point (1) and the destination point (4). With “through” you specify that the fourth repetition should also be executed, whilst the loop stops after the third pass. If you specify a higher value than the end value for the start value, SASS counts backwards. You have two elements in the loop: the name in the CSS is chosen, which gets a higher number with “#{$i}.” The variable – and therefore also the name – is increased by 1 for each run.
“#{}” is an “interpolation” in SASS. This allows you to combine a variable with a self-assigned identifier.
Secondly, write in curly brackets or indented what is supposed to happen. In our example, a size specification is manipulated with an increasing value for each run. A separate entry then appears in the CSS for each run:
CSS
.width-1 {
width: 11em;
}
.width-2 {
width: 12em;
}
.width-3 {
width: 13em;
}
.width-4 {
width: 14em;
}
.height-1 {
height: 25em;
}
.height-2 {
height: 50em;
}
.height-3 {
height: 75em;
}
The “@while” directive works very similar to “@for.” However, while the latter has fixed start and destination points, an “@while” loop contains a logical query: as long as a state is true, the statements are repeated. As you will see, we can achieve exactly the same result with the “@while” function:
SASS
$i: 1
@while $i < 5
.width-#{$i}
width: 10em + $i
$i: $i + 1
SCSS
$i: 1;
@while $i < 5 {
.width-#{$i} { width: 10em + $i; }
$i: $i + 1;
}
In this loop type, you first need to assign a value to the variable, since the directive itself does not require a start value. In the loop, you specify the status up to which the repetitions are carried out. In our example, the loop runs as long as the variable is less than 5. The statement within the loop is initially the same as with the “@for” example. Again, adjust the name of the variable element and increase its size. In addition, you need to include a command in the loop that increases “$i” on each pass, otherwise the loop will run until the SASS compiler is stopped. At the end, however, you get the same CSS code as you would in the “@for” loop.
The “@each” directive, on the other hand, works slightly differently. This loop is based on a list: the loop passes through a collection of data that you have defined. For each entry “@each” makes its own repetition. For example, it would be possible to generate the same result again like with the other loops, by specifying a list with the values 1,2,3, and 4. The real advantage of this loop, however, is that you can also enter other information besides numerical values in the list – e.g. use “@each” to insert different images into your design. You can either enter the data directly in the directive or enter the list in a variable first and then call it.
SASS
$list: dog cat bird dolphin
@each $i in $list
.image-#{$i}
background-image: url('/images/#{$i}.png')
SCSS
$list: dog cat bird dolphin;
@each $i in $list {
.image-#{$i} { background-image: url('/images/#{$i}.png'); }
}
Here you will also need a variable. This takes the name of one of the entries in the list with each run. The name is integrated into both the name of the code block and the image’s file name. In order for the design to work later, you first need to have stored the corresponding images under the specified path. The loop automatically ensures that the variable takes over the next entry.
CSS
.image-dog {
background-image: url("/images/dog.png");
}
.image-cat {
background-image: url("/images/cat.png");
}
.image-bird {
background-image: url("/images/bird.png");
}
.image-dolphin {
background-image: url("/images/dolphin.png");
}
Branching
In addition to loops, SASS provides you with another means that comes from the world of programming: branching according to the if-then-else principle. With the “@if” directive, you only execute a statement if a certain state exists, otherwise another command takes effect. Aside from the directive, there is also a function if(). Both are independent of each other, but can also occur together. The function itself can easily be explained. It contains three parameters: the conditions, and two different outputs. The first output is output if the first parameter is true, otherwise the function plays the third parameter.
SASS
$black: #000000
$white: #ffffff
$text-color: $black
body
background-color: if($text-color == $black, $white, $black)
SCSS
$black: #000000;
$white: #ffffff;
$text-color: $black;
body {
background-color: if($text-color == $black, $white, $black);
}
In our example, the function checks whether the variable “$text-color” is set to black. In this instance (like the above example), the background is displayed in white. In any other case, the CSS would set the background to black. As you can see from this example, the branches are not necessarily suitable for designing an entire website. Both directive and function are primarily useful in mixins or partials. This allows the template to respond better to what happens in the final design for values. Conversely, if you already know that your text color is black, you don’t need to write a complex branch to make the background white.
Functions have the property of reproducing a single value. For more complex requirements, use the “@if” directive. This also has the advantage that they can distinguish between more than two cases:
SASS
$black: #000000
$white: #ffffff
$lightgrey: #d3d3d3
$darkgrey: #545454
@mixin text-color($color)
@if ($color == $black)
background-color: $white
@else if ($color == $white)
background-color: $black
@else if ($color == $lightgrey)
background-color: $black
@else
background-color: $white
p
@include text-color($lightgrey)
SCSS
$black: #000000;
$white: #ffffff;
$lightgrey: #d3d3d3;
$darkgrey: #545454;
@mixin text-color($color) {
@if ($color == $black) {
background-color: $white;
}
@else if ($color == $white) {
background-color: $black;
}
@else if ($color == $lightgrey) {
background-color: $black;
}
@else {
background-color: $white;
}
}
p {
@include text-color($lightgrey);
}
The directive’s syntax theoretically allows you to create a case for each value provided. Make sure to follow the initial “@if” with the “@else” directive, which you can call as often as you want in combination with “if.” Just the last “@else” remains free, you need to cover all other cases.
Comments
It also makes sense to add comments to the SASS source code. Through a meaningful commentary, the document will remain comprehensible for you and others in the future. Especially if you want to set up templates for other users, you help them with comments during editing. Many web designers also use comments to structure the code more clearly. Most programming and markup languages have the ability to insert text into the code that is ignored when compiling or parsing. This text is only of interest to humans, not computers.
Programmers and web designers also use comments to explain their code: to do this, you place a block code that you do not currently need, but do not want to delete the source code for, in the corresponding comment markers.
Each language has a specific method for commenting out text. In SASS, you do this in two different ways. On the one hand, the same option is available to you as in CSS: /* */. Use this method to comment out several lines directly. You can often find comments in CSS or SASS, where each line in the comment block starts with an asterisk. However, this is just a convention, not a necessity.
/* This is a comment.
Everything between the corresponding markings
will be included. */
When commenting, it is not important whether you write your code in SCSS or “indented syntax.” Comments work the same in both SASS syntaxes.
In addition to the method we already know from CSS, you can also comment out individual lines in SASS with //:
// These objectives are a commentary.
// So is this line.
The difference between the two methods is also that with the default settings the first variant is transferred into the compiled CSS, whilst the second variant is simply lost. Either way, you should let a CSS document with comments in the code go online as a product version. To do this, use a minimised version that browsers can load faster.