Senior Tips & Tricks

The hard-won habits that keep a Sass codebase fast, small and pleasant years in.

A closing grab-bag of practices that separate a codebase you enjoy maintaining from one you dread. None are exotic; all are the kind of thing you wish someone had told you earlier.

Keep the output honest

  • @extend sparingly. Placeholders (%name) with @extend share styles with zero duplication, but they hoist and reorder selectors in ways that surprise people. For parameterised reuse, prefer a mixin; for a shared base class, prefer a real class.
  • Mixins duplicate; that's fine. A mixin repeats its declarations at each call site. gzip loves repetition, so the real cost is smaller than it looks — optimise for clarity first.
  • Emit custom properties for anything runtime. Colours, spacing a component might re-theme — go through var(). Keep pure build-time values as Sass.

Keep the source maintainable

  • One source of truth. Every value traces back to a token map. A raw hex in a component file is a bug waiting to drift.
  • Private members. Prefix helpers with - or _ (@function -clamp()) so @forward won't leak your internals.
  • Never @import. It's deprecated and slated for removal — @use/@forward only.

Example

Example · css
@use 'sass:map';

// Private helper: the leading '-' keeps it out of @forward
@function -contrast($bg) {
  @return if(lightness($bg) > 55%, #111, #fff);
}

// Placeholder + @extend: shared base, no duplication...
%card-base {
  border-radius: 8px;
  box-shadow: 0 1px 3px rgba(0,0,0,.12);
}
.card    { @extend %card-base; }
.panel   { @extend %card-base; }
// -> .card, .panel { border-radius: 8px; box-shadow: ... }

// ...vs a mixin when you need a parameter
@mixin surface($bg) {
  background: $bg;
  color: -contrast($bg);      // auto-readable text
}
.tag--brand   { @include surface(#CC6699); }
.tag--neutral { @include surface(#f3f4f6); }

When to use it

  • A senior developer uses @debug to inspect a computed Sass map value mid-compilation rather than guessing why a generated color looks wrong.
  • A team creates a single _index.scss in each folder using @forward so every internal file changes require only one update to the public API, not every consumer.
  • A developer uses CSS custom properties for runtime-switchable values and Sass variables only for compile-time constants, cleanly separating the two concerns.

More examples

Using @debug to inspect values

Prints the computed values of Sass expressions to the terminal during compilation, acting as a printf-style debugger for Sass logic.

Example · css
@use 'sass:color';

$brand: #2563eb;
$hover: color.adjust($brand, $lightness: -10%);

@debug 'brand: #{$brand}';
@debug 'hover: #{$hover}';
// Outputs to stderr during compilation — remove before shipping

Folder index for stable public API

An index file hides the internal file structure; adding or renaming component partials never breaks external consumers.

Example · css
// components/_index.scss
@forward 'buttons';
@forward 'cards';
@forward 'forms';

// Other files just write:
// @use '../components';
// regardless of how many files are inside components/

Sass vars for constants, custom props for runtime

Uses a Sass variable for the fixed breakpoint pixel value and a CSS custom property for spacing that can shift responsively at runtime.

Example · css
// Sass variable — compile-time constant, never changes at runtime
$breakpoint-md: 768px;

// CSS custom property — can be changed by JS or media queries at runtime
:root {
  --spacing: 1rem;
}

@media (min-width: $breakpoint-md) {
  :root { --spacing: 1.5rem; }
}

Discussion

  • Be the first to comment on this lesson.