Writing Modern Sass

Paul Vidal
6 min readAug 10, 2021

Sass is a preprocessor scripting language that is compiled or interpreted into CSS. As it extends CSS, providing it with new features such as variables, nesting, partials, modules, mixins, and inheritance, it is described by the Sass team as “CSS with superpowers”, and it is a very useful tool for modern web development and design.

The rationale behind this article is that, while Sass is obviously very well-known, many developers using it are unaware of its recent developments, newest features, and best practices.

Current releases

Sass is currently available in two implementations: Dart Sass (written in Google’s Dart) and LibSass (written in C/C++). However, LibSass is deprecated, and, while it will continue to receive maintenance releases, there are no plans to add additional features or compatibility with new CSS or Sass features. So the LibSass team recommends that projects that still use it should move onto Dart Sass. Furthermore, the original implementation of Sass, written in Ruby, was terminated in 2019.

Sass is available for use and modification under the MIT License.

Installing Sass

NPM Sass package is a distribution of Dart Sass, compiled to pure JavaScript with no native code or external dependencies. Installing Sass through npm is the preferred way of using Sass in your projects. Using unofficial Sass IDE extensions (e.g. the popular Live Sass Compiler extension for Visual Studio Code) is a suboptimal solution, as these extensions tend to lag behind Sass's implementation of new features.

To install Sass in a project using Node.js simply run

npm install sass

Or

npm install -g sass

for installing it globally. Installing a package globally allows you to use the code in the package as a set of tools on your local computer, but it can cause dependency problems, as it throws away the isolation and reproducibility that a local package installation would give you.

Alternatively, you can download the package for your operating system from GitHub and add it to your PATH.

.sass versus .scss files

Sass provides two syntaxes:

  1. the original style, called indented syntax, uses a syntax similar to Haml, with indentation to separate code blocks and newline characters to separate rules. Sass follows strict indentation. Files implementing the original syntax have the .sass extension.
  2. the newer syntax, SCSS (standing for Sassy CSS), uses block formatting much like that of CSS, using braces to demarcate code blocks and semicolons to separate rules within a block. Scss does not require strict indentation, but semicolons and braces are mandatory. SCSS is a nested metalanguage, as any valid CSS is valid SCSS with the same semantics. Files using the Sassy CSS syntax are given the .scss file extension.

Using variables

Variables are storage locations paired with associated symbolic names, containing some information referred to as a value.

Variables in Sass provide a practical way of reusing information throughout your stylesheets. Any CSS value you may want to reuse, such as colors, font stacks, width values, directions, can become a valid variable.

For instance, if you want the text from elements extending both myClass and otherClass to have the same color shade of grey:

Example in SCSS

$font-stack:    Helvetica, sans-serif;
$primary-color: #7C7E7F;

.myClass {
font: 100% $font-stack;
color: $primary-color;
}
.otherClass{
color: $primary-color;
}

Example in Sass:

$font-stack:    Helvetica, sans-serif
$primary-color: #7C7E7F

.myClass
font: 100% $font-stack
color: $primary-color
.otherClass
color: $primary-color

When the Sass is processed, it takes the variables defined for $font-stack and $primary-color and outputs normal CSS with our variable values placed in the CSS. As both myClass and otherClass have color: $primary-color, the text in both classes will have the same shade of grey. On the other hand, only the text from the myClass class will be styled for use the Helvetica font-family, as the $font-stack was not called from otherClass. We can easily see how variables are extremely powerful when one needs to keep brand colors consistent throughout a website.

Variables are equivalent to CSS custom properties but offer a much better syntax.

Nesting

Sass brings into stylesheets clear nested and visual hierarchy, letting you nest your CSS selector in a way that follows the same visual hierarchy of your HTML files (or that of classes and objects in traditional OOP languages).

However, excessive nesting is a bad practice to be avoided, as it may result in code that is hard to maintain.

Compare the following code snippets to understand how nesting results in code that is both more readable and easier to maintain:

Suppose you’re building a navbar or a menu. The <nav> tag may encapsulate multiple children. Using CSS we may write something along these lines:

nav ul {
margin: 0;
padding: 0;
list-style: none;
border-bottom: 1px solid black;
}
nav li {
display: inline-block;
}
nav a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
nav a:hover {
text-decoration: underline
}

Its SCSS version could be implemented as:

nav {
ul {
margin: 0;
padding: 0;
list-style: none;
border-bottom: 1px solid black;
}

li { display: inline-block; }

a {
display: block;
padding: 6px 12px;
text-decoration: none;
&:hover: {
text-decoration: underline;
}
}
}

The parent selector, &, used above, is a selector used in nested selectors to refer to the outer selector, making it possible to re-use the outer selector in more complex ways, such as adding pseudo-classes. When a parent selector is used in an inner selector, it’s replaced with the corresponding outer selector, instead of the normal nesting behavior.

Partials

Partials are Sass files that are only meant to be imported, and not complied on their own. Their filenames begin with _ (as in _example.scss).

A note on the @import rule

The use of the @import rule is now discouraged, and it’s being phased out. The main issue with @import is that it makes all variables, mixins, and functions globally accessible, and the @use rule addresses this problem, offering the possibility of setting up namespaces.

Modules

Modules are stylesheets loaded by the @use. The @use rule is used to load mixins, functions, and variables from other Sass stylesheets.

The @forward rule loads a Sass stylesheet and makes its mixins, functions, and variables available when your stylesheet is loaded with the @use rule, thus making it possible to organize Sass libraries across many files while allowing their users to load a single entry point file.

Inheritance

The @extend rule allows you to implement classes that inherit all the styles of another class and have their own specific rules.

Compare the following code snippets:

CSS:

.error {
border: 1px #f00;
background-color: #fdd;
}

.error--serious {
border-width: 3px;
}

SCSS:

.error {
border: 1px #f00;
background-color: #fdd;

&--serious {
@extend .error;
border-width: 3px;
}
}

More at-rules

@error

The @error rule notifies the user if the wrong types and formats are passed to a mixin or function. After the error is printed, Sass stops compiling the stylesheet and tells whatever system is running it that an error occurred.

@warn

The @warn rule works similarly to the @error rule explained above, and it’s used to ensure the correct types and formats are passed to your functions and mixins. The only difference is that it does not stop the compiling process once a warning is raised.

@debug

The @debug at-rule prints the value of the expression it is attached, along with its filename and line number.

--

--