🎨 Sass/SCSS Introduction and Setup
Plain CSS gets repetitive fast on real projects. Sass is a preprocessor that adds variables, nesting, and logic to CSS — then compiles down to the ordinary stylesheet the browser already understands. This lesson gets you from "what is it?" to a compiler running on your machine.
🎯 Learning Objectives
By the end of this lesson, you will be able to:
- Explain what a CSS preprocessor is and the problems Sass solves
- Distinguish the two syntaxes — indented Sass vs SCSS — and choose SCSS with confidence
- Describe the compilation pipeline that turns
.scssinto browser-ready.css - Install Dart Sass and compile files in watch mode using several workflows
- Lay out a modular partial-based folder structure for a Sass project
Estimated Time: 25–35 minutes • Difficulty: Beginner
Hands-on: Install Sass, compile your first SCSS file, and run the compiler in watch mode.
In This Lesson
What Is Sass?
Sass — Syntactically Awesome Style Sheets — is a CSS preprocessor. That means it is a language that looks like CSS but adds real programming features on top: variables, nesting, reusable blocks called mixins, functions, math, and even loops and conditionals. You write Sass, a tool compiles it, and out comes ordinary CSS that any browser can render.
The key idea is that browsers never see your Sass. They only ever load the compiled .css file. Sass is a tool for authoring stylesheets, not a new thing browsers had to learn.
📖 Key Terms
Preprocessor: a tool that transforms source you write into a different output format before it is used — here, Sass source into CSS.
Compilation: the step that runs the preprocessor and produces the final CSS file.
Dart Sass: the official, actively maintained Sass implementation. The old Ruby and Node-Sass engines are deprecated — always use Dart Sass today.
💡 Analogy — Sass is a kitchen appliance. Think of Sass as a food processor. Raw ingredients (your Sass code) go in, and a finished dish (CSS) comes out. Your dinner guests — the browser — only ever taste the final dish. They never see the appliance or the technique behind it.
Two Syntaxes: Sass vs SCSS
Confusingly, "Sass" names both the project and one of its two syntaxes. Here is the distinction:
- The indented syntax (
.sass) — the original. It drops braces and semicolons and relies on indentation, like Python. - SCSS (
.scss) — "Sassy CSS". It uses the exact braces-and-semicolons syntax of regular CSS, and every valid CSS file is already valid SCSS.
The same navigation styles, written both ways:
Indented Sass syntax
nav
ul
margin: 0
padding: 0
list-style: none
li
display: inline-block
a
display: block
padding: 6px 12px
text-decoration: none
SCSS syntax
nav {
ul {
margin: 0;
padding: 0;
list-style: none;
}
li {
display: inline-block;
}
a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
}
✅ Which should you learn?
Use SCSS. Because it is a superset of CSS, you can paste existing CSS in and improve it gradually, autocomplete works better, and nearly every framework and tutorial you will meet (Bootstrap, Bulma, design systems) ships SCSS. This entire module uses SCSS.
Why Use a Preprocessor?
Plain CSS is wonderfully simple, but on a large codebase its simplicity turns into pain: the same hex color copied into forty places, deeply repeated selector prefixes, no way to do arithmetic, and no real way to package a reusable chunk of styling. Sass targets exactly those gaps.
| Feature | What it gives you | Real-world use |
|---|---|---|
| Variables | Store a color, font, or size once and reuse it | One brand palette shared across an entire e-commerce site |
| Nesting | Mirror your HTML structure; write less | Component-scoped styles in a design system |
| Partials & modules | Split styles into small importable files | Theme systems for multi-brand companies |
| Mixins | Reusable, parameterized blocks of declarations | Consistent button and card styling everywhere |
| Functions | Compute and return values | Dynamic spacing and type scales |
| Loops & conditionals | Generate CSS programmatically | Utility-class generators, à la Tailwind |
⚠️ A note on CSS custom properties
Modern CSS has its own --variables, calc(), and even nesting. So is Sass obsolete? No — but the lines have blurred. Sass variables and math run at build time and disappear from the output; CSS custom properties live at runtime and can change with the cascade or JavaScript. Mature projects often use both: Sass for authoring conveniences (mixins, loops, partials) and CSS custom properties for runtime theming like light/dark mode.
How Compilation Works
Because browsers cannot read Sass, a compiler stands between your source and the browser. You edit .scss; the compiler watches for changes and regenerates .css; the browser loads that CSS.
Your HTML always links the compiled file, exactly as it would with hand-written CSS:
<link rel="stylesheet" href="dist/css/style.css">
Installing & Running Sass
There are several ways to get a compiler running. Pick the one that fits how you already work.
Method 1 — Global install (fastest to start)
If you have Node.js installed, add the official Dart Sass command-line tool globally:
npm install -g sass
Compile a file once:
sass input.scss output.css
Recompile automatically on every save with watch mode:
sass --watch input.scss output.css
Watch a whole folder, mapping a source directory to an output directory:
sass --watch scss:css
Method 2 — Project dependency (recommended for real projects)
Keeping Sass local to the project means every teammate compiles with the same version. Add it as a dev dependency:
npm install sass --save-dev
Then wire up scripts in package.json:
{
"scripts": {
"sass": "sass src/scss:dist/css --watch",
"sass:build": "sass src/scss:dist/css --style=compressed --no-source-map"
}
}
Run the watcher while developing, or the minified build for production:
npm run sass # develop with live recompile
npm run sass:build # one-off compressed output
Method 3 — Build-tool integration
Most modern bundlers understand SCSS with almost no configuration:
- Vite — just install
sassand import a.scssfile; no config needed. - Webpack — add the loader chain:
npm install sass-loader sass css-loader style-loader --save-dev. - Next.js / Astro / SvelteKit — install
sassand SCSS support turns on automatically.
Method 4 — VS Code extension (no terminal)
For quick learning without touching the command line, install the Live Sass Compiler extension. A "Watch Sass" button appears in the status bar; click it and it compiles on save.
What compiled output looks like
Given this SCSS:
$brand: #3b82f6;
.btn { color: $brand; }
the compiler emits plain CSS — the variable is gone, resolved at build time:
.btn { color: #3b82f6; }
A Modular Project Structure
The real payoff of Sass is splitting one giant stylesheet into small, focused partials. A partial is any file whose name starts with an underscore (_variables.scss). The leading underscore tells the compiler "don't build this into its own CSS file — it is only meant to be pulled into another file."
project/
├── src/
│ ├── scss/
│ │ ├── main.scss # entry point — pulls in every partial
│ │ ├── _variables.scss # colors, fonts, spacing tokens
│ │ ├── _base.scss # resets and base element styles
│ │ ├── _layout.scss # header, footer, grid
│ │ ├── _components.scss # buttons, cards, forms
│ │ └── _utilities.scss # helper classes
│ └── index.html
└── dist/
└── css/
└── main.css # the one compiled output
Only main.scss lacks an underscore, so it is the only file the compiler emits. Inside it, you pull the partials together. Modern Sass uses @use for this (we cover it fully in the next lessons); the older @import rule still works but is now deprecated:
// main.scss — modern loading with @use
@use 'variables';
@use 'base';
@use 'layout';
@use 'components';
@use 'utilities';
💡 Why the underscore convention matters
Without it, a folder of ten partials would produce ten stray CSS files. The underscore keeps your output to a single, clean stylesheet while your source stays neatly organized.
Hands-on Exercise
🏋️ Compile Your First SCSS File
Objective: Install Sass, write a tiny SCSS file that uses a variable and nesting, and watch it compile to CSS.
Instructions:
- Create a folder
sass-labwith subfoldersscss/andcss/. - Install Sass globally:
npm install -g sass. - In
scss/main.scss, write a variable and one nested rule (anavwith a nesteda). - Run
sass --watch scss:cssand confirmcss/main.cssappears. - Change the variable's value, save, and watch the CSS regenerate on its own.
💡 Hint
Define a variable at the top with the $name: value; syntax, then reference it inside a rule. Nest a child selector by placing its braces inside the parent's braces. Leave the --watch command running in its own terminal tab.
✅ Example solution
scss/main.scss:
$link-color: #3b82f6;
nav {
background: #0f172a;
a {
color: $link-color;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
After running sass --watch scss:css, css/main.css contains:
nav { background: #0f172a; }
nav a { color: #3b82f6; text-decoration: none; }
nav a:hover { text-decoration: underline; }
Notice how the nested rules flattened into standard CSS selectors and the variable resolved to its hex value.
Best Practices
✅ Do
- Use Dart Sass and the SCSS syntax — they are the current, supported standard.
- Keep partials small and single-purpose; assemble them in one entry file.
- Run the compiler in watch mode while developing so feedback is instant.
- Commit your
.scsssource and either build CSS in your pipeline or commit the compiled output — be consistent about which. - Ship
--style=compressedCSS to production.
⚠️ Don't
- Don't install node-sass — it is deprecated and unmaintained.
- Don't hand-edit the compiled
.cssfile; your next compile will overwrite it. - Don't reach for Sass just to declare a couple of variables — for that, plain CSS custom properties may be enough.
🎯 Quick Quiz
Question 1: Why can't a browser load a .scss file directly?
Question 2: What does the leading underscore in _variables.scss tell the Sass compiler?
Question 3: Which syntax should most new projects use, and why?
Summary & Quiz
🎉 Key Takeaways
- Sass is a CSS preprocessor that adds variables, nesting, mixins, functions, and logic to CSS.
- SCSS is the preferred syntax — a superset of CSS that every framework uses.
- Browsers never read Sass; a compiler turns
.scssinto.css, ideally in watch mode. - Use Dart Sass, installed globally, per-project, or through a bundler.
- Partials (underscore-prefixed files) let you split styles into small modules that assemble into one output.
📚 Further Reading
🚀 What's Next?
Now that Sass compiles on your machine, the next lesson digs into the three features you'll reach for every single day: variables, nesting, and partials. You'll learn variable scope, the powerful & parent selector, and how to architect a project with the 7-1 pattern.
🎉 Great start!
You have a working Sass compiler and a mental model for how it fits into your workflow. Time to start writing real SCSS.