Best Practices
Practical tips for maintainable, professional Sass.
A checklist to keep Sass projects clean as they grow.
Do
- Use
@useand@forward, never the deprecated@import. - Keep nesting shallow (three levels max).
- Store tokens in maps; expose them through accessor functions.
- Mark configurable variables with
!default. - Prefer
math.div()andcolor.scale()over deprecated helpers. - Give partials clear names and group them with an
_index.scss.
Avoid
- Deeply nested, over-specific selectors.
- Overusing
@extendon real classes — prefer placeholders. - Huge single files — split into partials.
- Magic numbers — name them as variables.
Good Sass reads like a well-organized design system: small files, clear names, and tokens driving everything.
Example
// Good: tokens + accessor + shallow nesting + modern APIs
@use 'sass:color';
@use 'sass:map';
$brand: (primary: #CC6699);
@function brand($k) { @return map.get($brand, $k); }
.btn {
background: brand(primary);
&:hover { background: color.scale(brand(primary), $lightness: -10%); }
}When to use it
- A senior developer enforces a naming convention of BEM + Sass nesting at max 2 levels to keep specificity flat and overrides predictable.
- A team adds sass-lint to their CI pipeline to catch over-nesting, missing !default flags on library variables, and deprecated @import usage automatically.
- A developer documents their _mixins.scss with JSDoc-style comments above each mixin so editors surface parameter types and descriptions as autocomplete hints.
More examples
Keep specificity flat with BEM
Limits nesting to BEM element and modifier suffixes on the block, producing single-class selectors with minimal specificity.
// Avoid: nesting that raises specificity
.card .card__title .card__title--featured {}
// Prefer: flat BEM + shallow nesting
.card { /* base */ }
.card {
&__title { font-size: 1.25rem; }
&__title--featured { color: #2563eb; }
}Document mixins and functions
SassDoc-style triple-slash comments document parameter types and return value so editors can surface hints and teams understand the API.
/// Convert px to rem.
/// @param {Number} $px - Pixel value to convert
/// @param {Number} $base [16] - Root font size
/// @return {Number} rem value
@use 'sass:math';
@function rem($px, $base: 16) {
@return math.div($px, $base) * 1rem;
}Keep abstracts side-effect-free
Abstract files (variables, mixins, functions) must never emit CSS on their own — output belongs only in base, component, or layout files.
// abstracts/_mixins.scss — NO output, only definitions
@mixin flex-center {
display: flex;
align-items: center;
justify-content: center;
}
// base/_layout.scss — output goes here
@use '../abstracts/mixins' as mx;
.hero { @include mx.flex-center; }
Discussion