Sass is a CSS preprocessor that is becoming vital in the front-end engineers’ toolbox. Sass gained popularity because of a couple of CSS pitfalls that it fixes.
It is also what Bootstrap 4 runs on. Meaning it would be really helpful to learn Sass in order to understand how to manipulate bootstrap code, rather than overriding the code (which is the custom method by most developers). Understanding Sass gives a better understanding of tools that are on a source code level.
When working with CSS, we are often working in a world of globals and can mistakenly style an element.
Custom CSS (even with CSS variables) is still very redundant. CSS was not designed for the kind of complex architecture we have today and we run into the problem of importing a style sheet inside another style sheet which may lead to a very large style base that may not be understood without proper documentation.
In this article, we will be focusing on why preprocessors are important with a particular emphasis on SASS and its ability to compose rules together. Using Sass gives a more logical approach to styling modern web components.
We will also look at why we use these preprocessors with demo examples showing how we break styling up into smaller specific components without forcing our users to download a lot of unneeded CSS files.
Before we go any further, this article assumes the following:
Sass can be added to your project in a number of ways, you can find all of the installment options here. For the sake of this article, we will be using npm by running:
npm install -g sass
When learning the fundamentals of web development, we are introduced to conventional CSS which involves working with and manipulating HTML using identifiers like Classes or IDs.
While working with CSS, we oftentimes have to beat the styling to get it to look the way we want it to. It is really stressful to organize large style sheets. And keeping the classes scoped to avoid styling things in an unintended way is almost tiring.
Even with the introduction of a CSS variable to reduce the repetition with declarations, there are a few issues with this concept that are solved with using a preprocessor. Such as having long variable names.
Even with the advent of CSS3, we still need to rely on techniques (that are basically hacks) to styling user interfaces. We can also notice that while writing HTML, there is a clear nested and visual hierarchy, which regular CSS doesn’t allow for.
Let’s look at the “solution” to the features missing in CSS.
These can basically be thought of as a program that lets you generate CSS from the preprocessor’s own unique syntax. CSS preprocessors generally add some features that don’t exist in pure CSS, such as mixin, nesting selector, inheritance selector. While also giving us a very structured way of writing style sheets. Examples of CSS preprocessors include LESS, stylus, Sass, PostCSS. As stated earlier, this article is focused on Sass as a preprocessor.
Now if you’re new to this concept of Sass you may wonder, ‘if Sass is the preprocessor, what is SCSS’? Well , because there is a bit of confusion in using Sass because of the lack of the semicolon ;
and curly brackets {}
, in place of that, it uses tabs and spaces.
In version 3 of Sass, the SCSS syntax was introduced as the main syntax for Sass, it contains all the features of CSS but allows for the use of the features of Sass. Either syntax works when styling and neither one is better than the other in my opinion. The need for SCSS was to make the learning curve and implementation of Sass faster and without errors.
Sass:
$font-stack: Helvetica, sans-serif $primary-color: #333 body font: 100% $font-stack color: $primary-color
SCSS:
$font-stack: Helvetica, sans-serif; $primary-color: #333; body { font: 100% $font-stack; color: $primary-color; }
In the above code example, we notice the difference in Sass and SCSS writing styles. Note that they both use $
to declare a variable.
When styling HTML files, SCSS enables you to have the same visual hierarchy of your HTML in your style sheet so you can actually map out your styling in a more understandable manner. For example, styling this index.html
:
<nav class = 'sidebar'> <ul> <li> <a> </a></li> </ul> </nav>
CSS:
nav ul { margin: 0; padding: 0; list-style: none; } nav li { display: inline-block; } nav a { display: block; padding: 6px 12px; text-decoration: none; }
SCSS:
nav { ul { margin: 0; padding: 0; list-style: none; } li { display: inline-block; } a { display: block; padding: 6px 12px; text-decoration: none; } }
We can see from the CSS code example above that we are able to deduce the structure of the HTML file while keeping the implementation short and simple. Another advantage of this is that it helps to avoid spelling errors plus you can see that we have scoped some rules so that they only apply within the nav
.
Descendant style rules apply in SCSS for example:
.container{ .left-area{ ... } }
What this means is that all the descendants of the container class which have the class = "left-area"
would be affected by the rules. Basic CSS selectors still apply to SCSS such as:
.container{ > .left-area{ ... } }
Now only classes that are immediate children of the container div will get the style.
If we wanted to modify a class by adding a class to it, we could make use of the parent selector, it is mostly used in situations where adding a secondary style changes the style of the element. Which would also play the role of modifiers.
.container{ & .right-area{ background-color : #0000 } }
We can also use the parent selector to scope roles to another class like this:
button{ color:#349; .theme-dark &{ color: #fff } }
From the code example, the color #fff
only applies to the .theme-dark
class because of the parent selector.
Usually, in CSS, we have various style sheets linked by using @import
to bring in another style sheet into the main CSS. What does this mean for the user? This would mean having to download extra CSS files.
What if there was a way to resolve all these inputs into a single CSS file using SCSS. The concept of variables in CSS comes from a JavaScript approach.
Note that @import
in SCSS are used to get partials into other SCSS files but they do not become CSS files. They are denoted by having _
before the name.
Global variables: As the name suggests, these are variables that can be accessed within a block of CSS. If you are familiar with scoping in JavaScript, you would understand global variables.
Variables in SCSS always begin with a dollar sign $
.
$color: #f002 .color{ $text_color: #ddd; background-color: $color; color: $text_color; text-shadow:0 0 2px darken($text_color, 40%); }
From the code above, we notice that the $text_color
can only be accessed within the block of code.
Another awesome feature of SCSS is its ability to package reusable styling together and allow for import into another style block on demand to reduce redundancy in code.
Creating a mixin is as simple as adding a @mixin
followed by the mixin name before the block of styles, like this:
@mixin {insert name} { //write CSS code here }
To use Mixins within code blocks we have to use the @include
followed by the name of the mixin then a semicolon. This helps to use a predefined mixin within a code block:
.nav { @include {mixin name} }
Another way of using mixins is by using arguments, like a function in JavaScript we can declare a global variable and set it as a parameter for a mixin:
@mixin text-color($color){ background-color: $color; color: white; } //import .name{ @include text-color(orange); } .background{ @include text-color(white) }
Now imagine if we wanted a default value for a mixin and would change or reassign this value in different code blocks, we would use some arguments. To show this, I will refactor the previous code example:
@mixin text-color($color : #fff){ background-color: $color; color: white; } //import .name{ @include text-color(orange); } .background{ @include text-color($color: white) }
What this does is, it sets a default color for the mixin as a base, but it is modifiable by reassigning. We could also set the value to null
in order to only use the argument we need in the mixin:
@mixin text-color($color : null){ background-color: $color; color: #038; } //import .name{ @include text-color(); } .background{ @include text-color(#fff) }
What this does is it makes the values that are displayed as null to have no value in the @include
importation, but displays the other value by default.
Passing a deceleration block:
@mixin text-color($color){ color: $color; .extra{ @content } } //import .name{ @include text-color(#fff){ color: blue; } }
The code block basically allows us to be able to keep the styling simple by styling the parent class and also being able to define the inner class.
Functions in SCSS are a big part of the features of SASS, they allow you to define complex operations that are re-usable throughout your style sheet. There are a lot of inbuilt Sass functions that can help. Check out the documentation for more information.
Here is a list of some of the functions you should be familiar with
We can also write our own Sass functions:
$width: 4px; @function double($x){ @return 2 * $x; } .thin-border{ border-width: $width } .thick-border{ broder-width:double($width) }
The function above just doubles the value when the function is called with the normal width as a parameter.
This feature is brilliant as it allows us to alternate a specific style, based on the value of another style using the @if
and @else
declarations. For instance, dynamically increasing a line-height for different values of font-size.
@mixin modify($size){ font-size: $size; @if $size > 18{ line-height: $size; } } //import .name{ @include modify(24px) }
@for
for iteration and control flow this can be used with mixins and functionsIn this article, we have attempted to understand the basics of writing functional CSS with SCSS and also looked at some Sass/SCSS principles in general. I hope we put these practices into play towards writing more stress-free and optimized styling for our applications. Happy coding! 😄
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.
LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app, mobile app, or website. 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 and mobile apps — start monitoring for free.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowExplore use cases for using npm vs. npx such as long-term dependency management or temporary tasks and running packages on the fly.
Validating and auditing AI-generated code reduces code errors and ensures that code is compliant.
Build a real-time image background remover in Vue using Transformers.js and WebGPU for client-side processing with privacy and efficiency.
Optimize search parameter handling in React and Next.js with nuqs for SEO-friendly, shareable URLs and a better user experience.