Episode 1 — Fundamentals / 1.7 — Working With SASS

1.7.c — Variables & Nesting

In one sentence: SCSS variables ($name: value) let you define values once and reuse them everywhere, while nesting lets you write selectors that mirror your HTML structure — but keep nesting shallow to avoid specificity nightmares.

Navigation: ← 1.7.b — SCSS vs SASS & Setup · 1.7.d — Partials & Imports →


1. SCSS variables

Declaring and using

$primary:    #3b82f6;
$font-stack: 'Inter', sans-serif;
$spacing-md: 1rem;

.btn {
  background: $primary;
  font-family: $font-stack;
  padding: $spacing-md;
}

Compiles to:

.btn {
  background: #3b82f6;
  font-family: "Inter", sans-serif;
  padding: 1rem;
}

Variables are replaced at compile time — the browser never sees $primary.


2. Data types

TypeExampleNotes
Number16px, 1.5, 100%With or without units
String'Inter', bold, "hello"Quoted or unquoted
Color#3b82f6, rgb(59,130,246), blueAny CSS color format
Booleantrue, falseUsed in @if conditions
NullnullProperty is omitted from output
List1rem 2rem 3rem, (a, b, c)Space or comma separated
Map('sm': 640px, 'md': 768px)Key-value pairs in parentheses

3. Variable scope

$color: red;            // global

.card {
  $color: blue;         // local — only inside .card block
  background: $color;   // blue
}

.footer {
  color: $color;        // red (global)
}

Use the !global flag to override the global variable from inside a block — but avoid this; it makes code hard to trace.

.card {
  $color: blue !global;   // now global $color is blue everywhere after this point
}

!default — safe defaults

$primary: #3b82f6 !default;

"Use #3b82f6 only if $primary is not already defined." This is how libraries let consumers override theme variables before importing.


4. Nesting selectors

Basic nesting

.nav {
  background: #1e293b;

  ul {
    list-style: none;
    display: flex;
  }

  a {
    color: white;
    text-decoration: none;
  }
}

Compiles to:

.nav { background: #1e293b; }
.nav ul { list-style: none; display: flex; }
.nav a { color: white; text-decoration: none; }

5. The & parent selector

& refers to the entire parent selector at that point in the nesting. It is essential for pseudo-classes, BEM naming, and modifier patterns.

.btn {
  background: $primary;

  &:hover {
    background: darken($primary, 10%);
  }

  &:focus-visible {
    outline: 2px solid $primary;
  }

  &--large {
    padding: 1rem 2rem;
    font-size: 1.25rem;
  }

  &__icon {
    margin-right: 0.5rem;
  }
}

Compiles to:

.btn { background: #3b82f6; }
.btn:hover { background: #2563eb; }
.btn:focus-visible { outline: 2px solid #3b82f6; }
.btn--large { padding: 1rem 2rem; font-size: 1.25rem; }
.btn__icon { margin-right: 0.5rem; }

Without &, nesting would produce .btn :hover (descendant) instead of .btn:hover (pseudo-class on same element).


6. Nesting properties

SCSS also allows nesting property namespaces (less commonly used):

.card {
  font: {
    family: 'Inter', sans-serif;
    size: 1rem;
    weight: 400;
  }
}
// Outputs: font-family, font-size, font-weight

7. Nesting best practices

RuleWhy
Max 3 levels deepDeeper nesting produces long selectors with high specificity — hard to override
Avoid nesting element selectors blindly.sidebar div p span breaks when HTML structure changes
Use & for pseudo-classes and BEMKeeps related styles co-located without deep nesting
Flatten when selectors get longIf the compiled selector is unreadable, unnest

Bad vs good

// ❌ Too deep — compiled selector: .page .sidebar .widget .title span
.page {
  .sidebar {
    .widget {
      .title {
        span { color: red; }
      }
    }
  }
}

// ✅ Flat, intentional nesting
.widget__title {
  span { color: red; }
}

8. SCSS variables vs CSS custom properties

SCSS Variables ($var)CSS Custom Properties (--var)
Resolved atCompile timeRuntime (browser)
Available inSCSS files onlyCSS, JavaScript, DevTools
Cascade / inheritNo — static replacementYes — cascade and inherit through DOM
Dynamic changesNo (requires recompile)Yes — change with JS or media queries
Use caseBuild-time constants (breakpoints, base sizes)Theme switching, dark mode, per-component overrides

Best practice: Use SCSS variables for values the compiler needs (breakpoints in @if, loop bounds). Use CSS custom properties for values the browser needs to change (dark mode toggle, user preferences).

$breakpoint-md: 768px;           // compiler uses this in @media
:root {
  --color-primary: #{$primary};  // browser toggles this for dark mode
}

9. Key takeaways

  1. $variable: value; — defined once, used everywhere, resolved at compile time.
  2. SCSS has seven data types — numbers, strings, colors, booleans, null, lists, and maps.
  3. Nesting mirrors HTML structure but keep it to 3 levels max to avoid specificity problems.
  4. & is the parent selector — essential for pseudo-classes (:hover), pseudo-elements (::before), and BEM modifiers (&--active).
  5. SCSS variables and CSS custom properties solve different problems — use both where appropriate.

Explain-It Challenge

Explain without notes:

  1. What happens to $primary in the final CSS — does the browser see it?
  2. Why is deeply nested SCSS (4+ levels) considered an anti-pattern?
  3. When would you prefer a CSS custom property (--var) over a SCSS variable ($var)?

Navigation: ← 1.7.b — SCSS vs SASS & Setup · 1.7.d — Partials & Imports →