Table of Contents
Have you ever wanted to learn Sass, but you didn’t find a good tutorial? Chances are that you are quite good with CSS. However, you feel like there is a better way of working with CSS. You want to take your skills and efficiency to another level. In that cases, learning how to use preprocessor like Sass is one way to achieve that goal. This will be the goal of this mini series, to help you learn Sass. Today, you will learn about topics like variables, mixins, extends, imports and more. Let’s start!
Why Sass?
What are the main reasons why you should learn Sass, or at leas consider doing it? CSS is great and, with time, it is getting even better. One of the biggest changes in the recent time was that CSS finally “learned” to use variables. This is a big step forward. And, I think that there is even more to come. Yes, the future of CSS seems to be quite good. Still, I think CSS is far from being perfect. The biggest disadvantages of CSS are probably lack of any way to re-use style rules.
Sure, you can create special class with set of styles and then use it repeatedly. However, even this approach is quite limited. You can’t change the styles on the fly unless you add additional CSS to override the original. Also, you can’t use any conditions or parameters to switch between “versions” of the styles. Again, the only way is adding more CSS code. Also, you need to either put on the right place in the cascade. Or, you have to increase CSS specificity.
Another common problem with CSS was that there was no way to specify variables. If you wanted to re-use specific value across the project, you had to do it in the old fashioned way. Sure, there is nothing bad with it. However, imagine you would decide to change that value. Now, you would have to find every instance. This can be quite a feat in large code base. Luckily, the majority of text editors offers search & replace functionality.
Another problem with CSS is math. When you use plain CSS, you can’t use even simple calculations, adding, subtracting, multiplication or division. This problem also disappears when you learn Sass. You can use calc(), but Sass is more advanced. And, lastly, CSS can be quite hard to maintain. Without preprocessor, you can’t use atomic Design (modular CSS), SMACSS or anything like that. You have all CSS code in a single file. And, no, @import is not really a fix for that.
The Beginner’s Guide to Learn Sass
If you want to learn Sass, you have to install it first. You can install Sass in a coupe way. In case of Mac users, this is quite fast. You only need to install Sass gem via terminal. In case of Linux, you will need to install Ruby first and then Sass gem. You can install Ruby via package manager. For computers with Windows you need to install Ruby first as well. I suggest downloading Ruby installer as this is the easiest way to do it. After installing ruby, install Sass gem.
In cmd:
gem install sass
In terminal:
sude gem install sass
You can check if you have Sass gem installed on your computer with a simple command below. It should return specific version of the Sass gem. For example, Sass 3.4.23 (Selective Steve). If you see something similar to this, congrats, you are ready not only to learn Sass, but also to start using it. However, if you want to try Sass without installing anything, you can use online Sass playground called Sassmeister. This website will allow you to use and test Sass immediately.
In cmd/terminal:
sass -v
Nesting, ampersands and variables
Let’s start this journey to learn Sass with a couple of things that are easier. These are nesting, using ampersand and variables. I guess that you already know nesting from working with HTML or JavaScript. You can nest elements inside other elements or functions inside other functions. In CSS, there is no such a thing as nesting. Sass brings this feature to CSS. When you learn Sass, you can nest CSS selectors just like you do in HTML.
Sass:
// Example of nesting nav { ul { margin: 0; display: flex; list-style-type: none; } li { padding: 16px; } a { color: #212121; text-decoration: none; } }
CSS:
nav ul { margin: 0; display: flex; list-style-type: none; } nav li { padding: 16px; } nav a { color: #212121; text-decoration: none; }
Side note: Those two slashes (//) are used to mark comments in Sass. In Sass, you can use both. The difference between Sass comment (//) and CSS comment (/**/) is that Sass comments are not compiled into CSS. So, every comment you make using Sass syntax will stay in your Sass files. Any comment you make using CSS syntax will be compiled into CSS. In other words, you will find CSS comments in final CSS file, not Sass comments.
I should warn you that it is easy to go over the board with nesting. When you fall in love with it, you can create code that will result in over-qualified CSS. And, this can make work with CSS even bigger pain that before you learn Sass and started to using it. For this reason, I suggest nesting CSS selector to three levels at max, no more.
Sass:
.level-one { .level-two { .level-three { color: red; } } }
CSS:
.level-one .level-two .level-three { color: red; }
The power of ampersand
One very useful feature you will probably use very often, after you learn Sass and nesting, is ampersand. Ampersand allows you to reference parent selector. You simply replace the parent selector with this character. You can use this for with pseudo-classes such as :before, :after, :hover, :active, :focus, etc. You can also use ampersand for adjoining, or adding, CSS classes to create selector with higher specificity.
Sass:
ul { &.nav-list { display: flex; } & li { padding: 8px 16px; } } a { position: relative; &:before { position: absolute; bottom: 0; left: 0; content: ""; border-bottom: 2px solid #3498db; } &:focus, &:hover { color: #3498db; &:before { width: 100%; } } &:active { color: #2980b9; } }
CSS:
ul.nav-list { display: flex; } ul li { padding: 8px 16px; } a { position: relative; } a:before { position: absolute; bottom: 0; left: 0; content: ""; border-bottom: 2px solid #3498db; } a:focus, a:hover { color: #3498db; } a:focus:before, a:hover:before { width: 100%; } a:active { color: #2980b9; }
I have to mention that ampersand also allows you to use CSS combinators, such as the child combinator (>), adjacent sibling combinator (+) and the general sibling combinator (~).
Sass:
section { & + & { margin-top: 16px; } & > h1 { font-size: 32px; } & ~ p { font-size: 16px; } } // You can also omit the ampersand before the combinator and the result will be the same. section { + & { margin-top: 16px; } > h1 { font-size: 32px; } ~ p { font-size: 16px; } }
CSS:
section + section { margin-top: 16px; } section > h1 { font-size: 32px; } section ~ p { font-size: 16px; }
Finally, you don’t have to put the ampersand as first. You can use it in the end to change the selector entirely.
Sass:
section { body main & { background: #fff; } }
CSS:
body main section { background: #fff; }
Variables and more maintainable code
The last of the three I mentioned are variables. I have to say that variables were one of the main reasons why I wanted to learn Sass. Actually, I think that they were the number one reason. Work with CSS gets so much easier when you can make changes on a global scale by changing a single line of code. You no longer have to search for all occurrences of this or that value. You store the value inside a variable. Then, you have to change only that variable. Sass will do the rest.
As you can guess, this can immensely simplify and speedup your work. Also, it makes your styles much easier to maintain. Variables work with numbers, strings, colors, null, lists and maps. The only thing you must remember is to use “$” symbol every time you want to define a variable. Then, when you want to use that variable, well, you know what to do.
Sass:
// Declare variables $color-primary: #9b59b6; $color-secondary: #2c3e50; // Use variables a { color: $color-secondary; &:hover { color: $color-primary; } }
CSS:
a { color: #2c3e50; } a:hover { color: #9b59b6; }
One thing to keep in mind on your journey to learn Sass and use variables is scope. Variables in Sass works like variables in any programming language. Variables declared in global scope are accessible globally, local not.
Sass:
a { // locally defined variables $color-primary: #9b59b6; $color-secondary: #2c3e50; color: $color-secondary; &:hover { color: $color-primary; } } p { color: $color-secondary;// Undefined variable: "$color-secondary". }
This also means that you can use the same name for different variables without the worry of changing some. Just make sure to declare your variables in the right scope.
Sass:
$color-primary: #9b59b6; $color-secondary: #2c3e50; a { // local variables $color-primary: #fff; $color-secondary: #212121; color: $color-secondary; } p { color: $color-secondary; }
CSS:
a { color: #212121; } p { color: #2c3e50; }
Mixins and extends
Let’s take this journey to learn Sass on another level. When you are ready for more advanced Sass, a good place to start are mixins and extends. Do you remember when we were talking about the biggest disadvantages of CSS, namely re-usability of the code? This is where mixins and extends enters the game. Both these Sass features allow you to create re-usable chunks of code. It is safe to say that mixins and extends are similar to functions you know from JavaScript.
You create new mixin using “@mixin” directive and some name and put some styles inside it (inside curly brackets). Then, when you want to use that mixin you reference to it using “@include” followed by the name of the mixin. Extends work in a similar way. The difference is that extends don’t require creating some “extend”. Instead, you use CSS classes you already created. Then, when you want to use extend you use “@extend”, not “@mixin”.
Sass:
// Example of mixin @mixin transition($prop, $duration, $timing) { transition: $prop $duration $timing; } // Use mixin a { @include transition(all, .25s, cubic-bezier(.4,0,1,1)); }
CSS:
a { transition: all 0.25s cubic-bezier(0.4, 0, 1, 1); }
Sass:
// Random CSS class .btn { padding: 6px 12px; margin-bottom: 0; display: inline-block; font-size: 16px; } Examples of extend .btn--success { @extend .btn; background-color: #2ecc71; } .btn--alert { @extend .btn; background-color: #e74c3c; }
CSS:
.btn, .btn--success, .btn--alert { padding: 6px 12px; margin-bottom: 0; display: inline-block; font-size: 16px; } .btn--success { background-color: #2ecc71; } .btn--alert { background-color: #e74c3c; }
Mixins vs Extends
The advantage of mixins is that you can use parameters to make mixins more flexible. For example, you can add a simple condition and if statement to switch between two or more sets of rules. Every parameter starts with “$” symbol. Then, use that name inside the mixin. And, you can also set a default value to make the parameter optional. Setting a default value is like assigning value to variable. Use “$” symbol followed by colons and default value. Extends don’t have this ability.
Sass:
// Example of mixin with optional parameters @mixin transition($prop: all, $duration: .25s, $timing: cubic-bezier(.4,0,1,1)) { transition: $prop $duration $timing; } a { @include transition(); }
CSS:
a { transition: all 0.25s cubic-bezier(0.4, 0, 1, 1); }
When you want to change only some parameters and use default values for the rest, you can use the name of parameter when you use that mixin.
Sass:
@mixin transition($prop: all, $duration: .25s, $timing: cubic-bezier(.4,0,1,1)) { transition: $prop $duration $timing; } // Use different value only for parameter for duration a { @include transition($duration: .55s); }
CSS:
a { transition: all 0.55s cubic-bezier(0.4, 0, 1, 1); }
Another very useful feature of mixins is to use it along with “@content” directive. This way, you can provide the mixin with block of content. A good way to use this is for creating media queries.
Sass:
// Mixin for media query @mixin media($screen-width) { @media only screen and (max-width: $screen-width) { @content; } } // Use the media query mixin with @content directive .container { @include media(768px) { max-width: 690px; } } // Mixin for retina display media query @mixin retina { @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { @content; } } .hero { background-image: url(/images/image.png); @include retina { background-image: url(/images/image@2x.png); } }
CSS:
@media only screen and (max-width: 768px) { .container { max-width: 690px; } } .hero { background-image: url(/images/image.png); } @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2 / 1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { .hero { background-image: url(/images/image@2x.png); } }
Imports and partials
The last thing we will touch upon to help you learn Sass is @import directive. Along with variables, this was another major reason for me to learn Sass. With Sass, you can split your stylesheet into unlimited number of files. Then, you use @import directive to import these chunks into single file. When you compile this file, Sass will automatically import content from all files and create one CSS stylesheet. Make sure to use correct names of files to import. Otherwise, Sass will throw an error.
Sass:
// This is _base.scss file html, body { padding: 0; margin: 0; } html { font-size: 100%; } body { font: 16px "Roboto", arial, sans-serif; color: #111; } // This is _typography.scss file h1, h2, h3 { margin-top: 0; font-weight: 200; } h1 { margin-bottom: 26px; font-size: 40px; line-height: 52px; } h2 { margin-bottom: 18px; font-size: 27px; line-height: 39px; } h3 { margin-bottom: 18px; font-size: 22px; line-height: 26px; } // This is main.scss // Note: you don’t have to use “_” in filenames when you import files /* Main stylesheet */ @import 'base'; @import 'typography';
CSS:
/* Main stylesheet */ html, body { padding: 0; margin: 0; } html { font-size: 100%; } body { font: 16px "Roboto", arial, sans-serif; color: #111; } h1, h2, h3 { margin-top: 0; font-weight: 200; } h1 { margin-bottom: 26px; font-size: 40px; line-height: 52px; } h2 { margin-bottom: 18px; font-size: 27px; line-height: 39px; } h3 { margin-bottom: 18px; font-size: 22px; line-height: 26px; }
Important thing to mention is that you can use imports whenever you want. You can import file A in the middle of the file B and then import file B into your main Sass stylesheet. The only thing you must remember is to use the right order of files.
Sass:
// File _base.scss html, body { padding: 0; margin: 0; } @import 'typography'; nav { list-style-type: none; } nav a { text-decoration: none; } // File main.scss /* Main stylesheet */ @import 'base';
CSS:
/* Main stylesheet */ html, body { padding: 0; margin: 0; } h1, h2, h3 { margin-top: 0; font-weight: 200; } nav { list-style-type: none; } nav a { text-decoration: none; }
Closing thoughts on how to learn Sass
This is all I have for you today on how to learn Sass. My intention for this article was to give you enough information to get started with Sass. Hopefully, this article makes this journey to learn Sass as easy as possible for you. Keep in mind that what we discussed today were only the basics. We barely scratched the surface. If you want to not only learn Sass, but master it, there is more we need to talk about. Don’t worry. We will cover these advanced topics in another article next week.
For now, take some time, go through the topics we discussed today and practice your new knowledge. Doing so will help you prepare for the more advanced techniques and features Sass can provide you with. So, stay tuned for the sequel. Until next time, have a great day!
If you liked this article, please subscribe so you don't miss any future post.
If you'd like to support me and this blog, you can become a patron, or you can buy me a coffee 🙂