Supun Kavinda I started as a self-taught PHP developer before creating my own company, Hyvor. I am particularly interested in physics and machine learning.

The definitive guide to SCSS

10 min read 2809

The Definitive Guide to SCSS

Initially, frontend development was all about writing HTML, CSS, and JavaScript. However, over the last decade or so, it has become more complex and ever more interesting. The field’s continuous evolution has made it increasingly critical to stay on top of the latest frontend technologies and learn how to build websites more efficiently.

In this guide, we’ll demonstrate how to use SCSS — think of it as a way to write CSS with superpowers. I’ve broken it into three sections:

  1. Introduction to SCSS
  2. SCSS language syntax
  3. Using SCSS in real-world applications

If you already know the language and just want to learn how to use it in your application, feel free to jump to the third section.

1. Introduction to SCSS (and Sass)

Officially described as “CSS with superpowers,” SCSS (or Sass) offers a way to write styles for websites with more enhanced CSS syntax. In general, browsers do not know how to process SCSS features, such as functions, mixins, and nesting. We’ll need to convert them to regular CSS files to run them in the browser.

What’s the difference between SCSS and Sass?

This is where most beginners get confused. SCSS and Sass are two syntax flavors for the same concept. The difference between them is UI.

SCSS
Sass
Stands for Sassy CSS
Stands for Syntactically Awesome Style Sheets
Similar to CSS (uses curly braces and semicolons)
Uses strict indentation (like Python)
Any valid CSS is valid SCSS
CSS code cannot be used as SASS
.scss extension
.sass extension

Here’s an example of SCSS:

body {
  background-color:#000;
  color:#fff;
}

Below is an example of Sass.

body
  background-color:#000;
  color:#fff;

It’s up to you to choose one. Don’t stress on the decision — you can easily convert SCSS to Sass and vice versa with the sass-convert tool.

In this article, I’ll focus on SCSS mainly for two reasons.

  1. SCSS syntax is similar to CSS, so it’s easy to explain the advancements for someone who already knows CSS
  2. Once you know SCSS, it takes only a few minutes to learn Sass

Why SCSS?

TL;DR: CSS is inadequate.

We made a custom demo for .
No really. Click here to check it out.

Don’t get me wrong: CSS is cool, but not quite cool enough. The creators of SCSS had a lot of ideas to make developers’ lives easier and decided to build them into an entirely new language. Actually, to be clear, Sass was the original version of this new language; SCSS is an improved version they created later.

How to use SCSS in your website

Unfortunately, the features of SCSS have yet to be introduced in the CSS specs and, therefore, are not supported by browsers. To run SCSS code in a web browser, you must first convert it to CSS. We’ll discuss tools you can use for this and how to automate the process later.

2. SCSS language syntax

For this section, I’ll assume you already have some experience with CSS. I’ll introduce features of SCSS one by one and explain the syntax of each.

The structure of SCSS rules

The structure of SCSS follows that of CSS. First, choose one or more elements using IDs, classes, or other CSS selectors. Then, add styles.

In this example, we select the elements with button class and add some properties. This is valid as CSS code as well as SCSS code. It’s important to note that SCSS supports all CSS properties.

.button {
  display:inline-block;
  font-size:14px;
  padding:4px 10px;
}

Comments in SCSS

Both // (single-line) and /* */ (multi-line) comments are allowed in SCSS.

// this is a single-line comment

/* this is a multi-line comment */

Now let’s go over the basic enhancements of SCSS. We’ll discuss how to compile SCSS to CSS in the final section. For now, you can use CodePen to write and test your code. Make sure you select SCSS as the preprocessor in CSS settings.

For the examples below, I’ll use a simple anecdote in which you are using SCSS while your super-cool, old-school developer grandpa struggles with CSS. Let’s get started!

Nesting

Your grandpa styled his navbar like this with CSS:

nav {
  background-color:#333;
  padding:1em;
}
nav ul {
  margin:0;
  padding:0;
  list-style:none;
}
nav ul li {
  display:inline-block;
}

But you can do so with SCSS, like this:

nav {
  background-color:#333;
  padding:1em;
  ul {
    margin:0;
    padding:0;
    list-style:none;
    li {
      display:inline-block;
    }
  }
}

Much more organized and concise, right? You have two major advantages over your grandpa:

  1. You know that all the styles of nav and its children are between curly braces, so you don’t need to find them in the file or in multiple files
  2. You simply write less code, so there is no repetition

Keep in mind, however, that when you go much deeper with nesting, the CSS file can become much larger and browsers will need to do more work to style the elements. Try to keep the selectors shallow. For example, we can save several bytes by taking the styles of li to the outer scope.

nav {
  background-color:#333;
  padding:1em;
  ul {
    margin:0;
    padding:0;
    list-style:none;
  }
  li {
    display:inline-block;
  }
}

For larger projects, this can save a huge amount of bandwidth.

It’s important to make sure this process doesn’t create any conflicts. For example:

content {
  ul {
    li {
      font-style:italic;
    }
  }
  ol {
    li {
      font-decoration:underline;
    }
  }
}

In this case, we cannot bring the styles of li elements to the outer scope because they have different rules.

Here’s the bottom line: nesting makes code more clear, organized, and concise, but be careful not to overuse it.

Using & in nesting

Your grandpa shows off his magical button that changes color when you hover over it. His CSS code looks like this:

button {
  background-color: #535353;
  color: #000;
}
button:hover {
  background-color: #000;
  color: #fff;
}

You can achieve the same effect much more easily with SCSS by using the & character in nesting.

button {
  background-color: #535353;
  color: #000;
  &:hover {
    background-color: #000;
    color: #fff;
  }
}

& always refers to the upper selection. Below are some use cases.

.some-class {
  &:hover {
    /* when hovered */
  }
  &:focus {
    /* when focused */
  }
  & > button {
    /* selector equls to .some-class > button */
  }
  &-cool {
    /*** Notice this! ****/
    // selects .some-class-cool elements
  }
}

Variables

Variables store data. In SCSS, you can save any CSS value (even with units) in variables. Variables are defined using the $ symbol.

Variable declaration:

$my-font: Nunito, sans-serif;
$my-font-color: #ffd969;
$content-width: 660px;

Variable usage:

body {
  font-family: $my-font;
  color: $my-font-color;
  content {
    width: $content-width;
  }
} 

When Sass is converted to CSS, all the variables are replaced with their original values. SCSS variables are useful to keep fonts, colors, and other values consistent thought a website or web app.

The difference between SCSS and CSS variables

SCSS variables are replaced with values when converted into CSS variables. These conversions take place before they are served to the browser, so browsers don’t even know there were variables in the first place, they just see the values. On the other hand, CSS variables are much more powerful.

CSS-Tricks outlined several advantages of CSS variables:

  • They cascade; you can set a variable inside any selector to set or override its current value
  • When a variable’s value changes (e.g., media query or another state), the browser repaints as needed
  • You can access and manipulate variables in JavaScript

Does that mean Grandpa wins? Not exactly: you can use CSS variables in SCSS stylesheets, since any valid CSS is also valid SCSS. If you’re curious about CSS variables, you can learn more here.

SCSS variable scope

Some things to keep in mind:

  • All variables defined in the top level are global
  • All variables defined in blocks (i.e., inside curly braces) are local
  • Blocks can access both local and global variables
$my-global-variable: "I'm global";
div {
$my-local-variables: "I'm local";
}

Changing the values of SCSS variables

Changing values is done in the same way as declaring. When you change a variable, subsequent uses will have the new value while the previous uses remain unchanged.

$color: #fefefe;
.content {
  background-color: $color;
}

$color: #939393;
.footer {
  background-color: $color;
}

Here, .content will have the background color #fefefe while .footer will have #939393. Global variables won’t change unless we add the !global modifier.

$color: #111;
.content {
  $color: #222; // this is a new local variable
  background-color: $color; # 222
}
.footer {
  $color: #333 !global; // changes the global variable  
}

Mixins

Let’s outdo your grandfather’s CSS again, this time with mixins.

A mixin is a group of CSS declarations that can be reused. The syntax is similar to functions in JavaScript. Instead of the function keyword, use the @mixin directive. You can have arguments too. Calling the mixin is done via the @include statement.

Here’s how to use mixins to position elements to absolute center:

@mixin absolute-center() {
  position:absolute;
  left:50%;
  top:50%;
  transform:translate(-50%,-50%);
}
.element-1 {
  @include absolute-center();
}
.element-2 {
  @include absolute-center();
  color:blue;
}

First, we defined the absolute-center mixin. Then, we used it in multiple blocks.

Mixins with arguments

Below is an example of how to use arguments in mixins.

@mixin square($size) {
  width:$size;
  height:$size;
}
div {
  @include square(60px);
  background-color:#000;
}

Mixins with optional arguments

Optional arguments can be defined in the same way we declared SCSS variables.

@mixin square($width: 40px) {
  width:$size;
  height:$size;
}

Mixins with content blocks

Instead of arguments, we can send CSS rules to the mixins. Those rules can be used in the mixin using @content.

@mixin hover-not-disabled {
  &:not([disabled]):hover {
    @content;
  }
}
.button {
  border: 1px solid black;
  @include hover-not-disabled {
    border-color: blue;
  }
}

This approach allows us to reduce the repetition of the &:not([disabled]):hover part.

Importing SCSS (@import and @use)

Chunking code is an important practice when creating larger apps. Your grandpa can do this by creating multiple CSS files and adding them all to the HTML document.

<link rel="stylesheet" href="/path/to/css/1"></link>
<link rel="stylesheet" href="/path/to/css/2"></link> 
<link rel="stylesheet" href="/path/to/css/3"></link> 
<link rel="stylesheet" href="/path/to/css/4"></link> 
<link rel="stylesheet" href="/path/to/css/5"></link>

Grandpa’s process is tedious. It requires the browser to make many HTTP requests, which may slow down his website.

SCSS is much better because it enables you to combine chunked files before sending the code to the browser. That way, you only need to link only one CSS file (which is usually named something.bundle.css).

@import

The examples below demonstrate how to chunk files and import them into one parent file using @import.

normalize.scss:

body {
  padding:0;
  margin:0;
}
body, html {
  width:100%;
  min-height:100%;
}

styles.scss:

@import 'normalize';

content {
  max-width:660px;
  // and more styles
}

Assuming that both normalize.scss and styles.scss are in the same folder, we can import one to another, as shown above.

When using @import, all the variables, mixins, etc. become globally accessible, which is a problem when you have complex file structures and use libraries. For this reason, using @importis now officially discouraged.

The solution is @use.

@use

The basic usage of @use is the same as that of @import.

styles.scss:

@use 'normalize';

// other styles

Files imported with @use are called modules. To use mixins or variables of these modules, we have to call them using namespaces. By default, the namespace is the filename (without the extension).

src/_colors.scss:

$accent-color: #535353;
@mixin dark-background {
  background-color:#000;
  color:#fff;
}

styles.scss:

@use 'src/colors';
body {
  color: colors.$accent-color;
}
.dark-region {
  @include colors.dark-background;
}

You can also use a custom namespace using as.

@use 'src/colors' as c;
body  {
  color: c.$accent-color;
}

When _ is prepended to a file name of a SCSS file, the parser knows that it is a partial file and it is there only for importing. When importing, the _ part is optional. Note that we used src/colors to import src/_colors.scss.

Arithmetic operators

You can do some math in SCSS without Grandpa’s CSS calc() function. You can use +,-,/,*,%, direct values, and variables for calculations.

$content-width: 600px;
content {
  width:$content-width;
}
.inner-content {
  width: $content-width - 60px; // substraction
}
.outer-content {
  width: $content-width + 60px; // addition
}

Flow control rules

There are four types of flow control rules: @if /@else, @each, @for, and @while.

@if and @else– are similar to if and else in JavaScript.

// ex: using in mixins
@mixin theme($is-dark: false) {
  @if $is-dark {
    // styles for dark
  }
  @else {
    // styles for light
  }
}

@each is similar to for of in JavaScript.

// creating automated 
$sizes: 40px, 50px, 80px;
@each $size in $sizes {
  .icon-#{$size} {
    font-size: $size;
    height: $size;
    width: $size;
  }
}

Note: The #{$size} notation is used to make dynamic property names and selectors using variables. This is called interpolation.

@for is similar to for loops in JavaScript.

@for $i from 1 through 4 {
  .bubble-#{$i} {
    transition-delay: .3 * $i;
  }
}

@while (not often used) is similar to while loops in JavaScript.

By this point, you’ve learned the definition and history of SCSS, how it works, the difference between SCSS and Sass, and the SCSS language syntax. Now it’s time to actually create something to prove that your SCSS is better than your grandpa’s CSS.

3. Using SCSS in real-world applications

In this part, we’ll demonstrate two ways to compile Sass into CSS.

Before we get started, we have to install the sass command line, which is the easiest tool to preprocess CSS. If you’re using npm, use the following code.

npm i -g sass

Check the installation guide for some additional ways to install the sass command line.

With the sass command line, you can parse both .scss and .sass files into .css. It automatically detects SCSS and Sass files by extension and uses the correct parser.

sass source.scss destination.css

Designing a simple blog page with SCSS

To demonstrate the sass command line and to review the concepts outlined above, let’s design a simple blog with one component: content (we’ll skip the header and footer to make it clearer).

First, create a folder on your local machine (I named it my-blog) and navigate there.

cd /path/to/my-blog

Then, create two more folders.

mkdir source build

We’ll place the .scss files in the source folder and preprocessed .css files in the build folder.

Next, create an index.html file in the root, open it in your favorite text editor, and add some HTML code.

<!-- index.html -->
<html>
<head>
    <link rel="stylesheet" href="build/index.css">
</head>
<body>
    <content>
        <content>
            Blog content goes here
        </content>
    </content>
</body>
</html>

Now it’s time to create our new SCSS files. Our main file will be source/index.scss, and it will include other files.

To start writing SCSS, we’ll set up a watcher to compile source/index.scss into build/index.css in real time. Use the --watch option in the sass command line.

sass --watch source/index.scss build/index.css

Finally, create the chunked SCSS files.

// index.scss
@use 'normalize';

@use 'Content';
@use 'Footer';

body {
    background-color:#fafafa;
    font-family: Segoe UI, sans-serif;
}


// _normalize.scss
body, html {
    margin:0;
    padding:0;
}
* {
    box-sizing:border-box;
}
content {
    display:block;
}


// _colors.scss
$content-box: #fff;
$footer: #222;
$footer-font: #fff; 

To recognize them easily, I name components’ style files in the Content.scss format.

// Content.scss
@use 'colors' as colors;
body > content {
    padding:40px;
    margin:auto;
    width:660px;
    max-width:100%;
    & > content {
        background-color: colors.$content-box;
        min-height:600px; // to look cool
        border-radius:20px;
        box-shadow:10px 10px 40px rgba(0,0,0,0.06);
        padding:40px;
    }
}

Now that we’ve created a basic blog page, let’s add some media queries.

Adding Media Queries

Let’s say we need to remove the padding of the parent <content> element in mobile devices (<600px). We can do that it in two ways.

The conventional CSS way is to add media queries globally.

@media screen and (max-width:600px) {
  body > content {
    padding:0;
  }
}

The SCSS way is to add media queries inside selectors.

body > content {
  @media screen and (max-width:600px) {
      padding:0;
  }
}

Both methods are valid; you can use whichever you prefer. Some developers save all media queries in a single file (e.g., Mobile.scss).

SCSS with webpack or Gulp

While the sass command line is straightforward and easy to use, if you are using a bundler like webpack or Gulp, you can use plugins to parse SCSS to CSS on bundling. Check out the following guides for each bundler. One advantage of a bundler is that you can use it to parse, autoprefix, and minify at the same time.

Conclusion

You should now understand the basics of SCSS and how it is used in the real world. We’ve discussed the most widely used features of SCSS, but I encourage you to look over the SASS documentation for a deeper dive. Once you’re comfortable with the SCSS, you may want to look into built-in SCSS modules, which can make your life much easier when creating complex applications.

As for your super-cool developer grandpa — tell him to get with the times and switch over to SCSS.

Is your frontend hogging your users' CPU?

As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.https://logrocket.com/signup/

LogRocket is like a DVR for web apps, recording everything that happens in your web app or site. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.

Modernize how you debug web apps — .

Supun Kavinda I started as a self-taught PHP developer before creating my own company, Hyvor. I am particularly interested in physics and machine learning.

One Reply to “The definitive guide to SCSS”

Leave a Reply