How CSS and SCSS Work Together

SCSS (Sassy CSS, a syntax of Sass) compiles down to plain CSS, adding variables, nesting, mixins, and functions that CSS itself didn’t originally have. Worth knowing up front, since it changes when SCSS is actually necessary rather than just familiar: native CSS has since caught up on several of these — nesting and custom properties both now work without any preprocessor at all, with real, non-obvious differences from how the same thing works in Sass.

In this post: The core SCSS features · Compiling SCSS to CSS · Does modern CSS still need SCSS? · The nesting trap worth knowing before it bites · SCSS vs. CSS at a glance · Related reading


The core SCSS features

Variables store reusable values:

$primary-color: #3498db;
$font-size-large: 16px;

body {
  color: $primary-color;
  font-size: $font-size-large;
}

Nesting mirrors HTML structure in the stylesheet:

nav {
  ul {
    list-style: none;
    li {
      display: inline-block;
      a { text-decoration: none; }
    }
  }
}

Mixins are reusable style blocks, closer to functions than anything CSS itself offers:

@mixin flex-center {
  display: flex;
  justify-content: center;
  align-items: center;
}

.container {
  @include flex-center;
}

Functions handle calculations and value manipulation SCSS’s built-ins support natively:

.box {
  width: percentage(0.5); // Compiles to 50%
}

Extends share a style block across selectors without repeating it:

%button-styles {
  padding: 10px 20px;
  border-radius: 5px;
}

.btn-primary { @extend %button-styles; background-color: blue; }
.btn-secondary { @extend %button-styles; background-color: gray; }

Compiling SCSS to CSS

Worth a direct correction here: `node-sass` still shows up in older guides as an equal alternative to Dart Sass, but it’s been deprecated since 2020, wraps the also-deprecated LibSass, and hasn’t gained a new language feature since 2018 — including no support for newer CSS functions like `calc()`. Dart Sass is the real, current, actively maintained implementation:

npm install -g sass
sass style.scss style.css
sass --watch style.scss:style.css

The compiled output is plain CSS — a `.header` block with nested `.nav`, `li`, and `a` selectors in SCSS becomes ordinary flat-ish CSS rules like `.header .nav li a`, linked into HTML exactly like any hand-written stylesheet. Nothing about the deployed site knows or cares that SCSS was involved at build time.


Native CSS nesting is now Baseline widely available — but it isn’t a drop-in replacement for Sass nesting. The specificity behavior is genuinely different, and code that works fine in Sass can silently break when nested natively.

Does modern CSS still need SCSS?

Worth a genuine update to this post’s original framing: two of SCSS’s traditional selling points are no longer preprocessor-exclusive. Native CSS nesting is now Baseline widely available — supported across Chrome 120+, Edge 120+, Firefox 117+, and Safari 17.2+, well over 90% of global browser usage — with no build step required. Native CSS custom properties (`–variable-name`) cover much of what SCSS variables did, and are covered in more depth in this site’s CSS cheat sheet. For a project that only needed SCSS for nesting and variables, that’s a real, current reason to reconsider whether a preprocessor and build step are still pulling their weight — not a reason SCSS is obsolete, since mixins, functions, and `@extend` still have no native CSS equivalent at all.


The nesting trap worth knowing before it bites

Worth understanding before assuming native CSS nesting is a mechanical find-and-replace for Sass nesting — it genuinely isn’t, in two specific, verified ways:

  • Specificity wrapping. Native nesting wraps the parent selector in `:is()`, which takes on the specificity of its most specific member. Nest a rule under a comma-separated list that includes an ID — `.card, #featured { … }` — and both branches silently inherit ID-level specificity, even the `.card` one. A later class-based override that worked fine in Sass can mysteriously stop applying, with no error to explain why.
  • No string concatenation. SCSS’s `&__element` pattern (the backbone of typical BEM naming, mentioned as a best practice earlier in this post) doesn’t work in native CSS nesting at all — `&` there is a live selector reference, not a string to glue text onto. A bare class nested without `&` also means something different than it does in Sass: `.active` nested inside `.chip { .active { … } }` compiles to the descendant selector `.chip .active`, not the compound `.chip.active` most people actually intend — `&.active` is required for that.

Both are the kind of thing that breaks silently rather than throwing an error — worth testing the actual compiled/computed selector rather than assuming Sass habits transfer directly, if a project starts mixing native nesting into a codebase that grew up on Sass conventions. A gradual migration is usually safer than converting an entire SCSS codebase to native nesting in one pass — catching a specificity regression in a small, isolated component is far easier than tracking one down across a whole stylesheet that changed all at once.


SCSS vs. CSS at a glance
FeatureNative CSS (2026)SCSS
VariablesSupported (custom properties)Supported
NestingSupported, different specificity rulesSupported
Mixins / reusable blocksNot availableSupported
Modularity (partials/imports)Manual effort requiredBuilt-in
Custom functionsLimitedSupported

Frameworks like Bootstrap, Bulma, and Foundation are still built on SCSS for their own source and customization layer, regardless of what native CSS can now do on its own — worth knowing that adopting one of those still means working with SCSS at the framework level, even in a project that otherwise wrote plain CSS.



SCSS still earns its place for mixins, functions, and genuine modularity — the honest update is that “nesting” and “variables” alone are no longer reasons to reach for a preprocessor by default, and worth re-evaluating on a project that adopted SCSS specifically for those two features and nothing else. Whichever direction a given project lands on, the specificity and selector-concatenation differences above are worth understanding either way, since even a project staying fully on SCSS will eventually run into native-nested third-party CSS it doesn’t control.

App Catalog Authentication Automation Backup Compliance Content Type CSS Flows Google Javascript Limitations List Metadata MFA Microsoft Node NodeJs O365 OneDrive Permissions PnP PnPJS Policy PowerApps Power Automate PowerAutomate PowerPlatform PowerShell React ReactJs Rest API Rest Endpoint Security Send an HTTP Request to SharePoint SharePoint SharePoint List SharePoint Modern SharePoint Online SPFX SPO Sync Tags Teams Termstore Versioning

Leave a Comment

Your email address will not be published. Required fields are marked *