Migration & Modern CSS
Navigate the transition from Sass to modern CSS — migrate variables to custom properties, evaluate PostCSS alternatives, and decide when Sass still adds value.
Sass Variables to CSS Custom Properties
CSS custom properties are runtime values that cascade — Sass variables are compile-time only. Migrate theme values, dynamic properties, and anything JavaScript needs to read into custom properties.
Keep Sass variables for compile-time logic: breakpoint maps, spacing calculations, and loop-generated utilities. Use a hybrid approach where Sass generates custom property declarations.
- CSS variables support runtime theme switching; Sass variables do not
- Sass still adds value for loops, mixins, and compile-time math
- Migrate incrementally — one component at a time
// Before: Sass only
$primary: #2563eb;
.btn { background: $primary; }
// After: hybrid
$colors: ('primary': #2563eb);
:root {
@each $name, $val in $colors {
--color-#{$name}: #{$val};
}
}
.btn { background: var(--color-primary); }PostCSS as an Alternative
PostCSS transforms CSS with JavaScript plugins — autoprefixer, nesting, custom media, and postcss-preset-env polyfill future CSS. It is not a preprocessor but achieves similar goals with standard CSS syntax.
Native CSS nesting (2023+) reduces the need for Sass nesting. CSS @layer manages cascade. Evaluate whether your Sass usage is truly needed or habit.
/* Native CSS nesting (modern browsers) */
.card {
padding: 1rem;
& .title { font-size: 1.25rem; }
&:hover { box-shadow: var(--shadow-md); }
}
/* PostCSS autoprefixer adds vendor prefixes automatically */From @import to @use
The Sass module system is mandatory for new projects. Migrate @import to @use/@forward incrementally. The sass migrator tool automates much of this conversion.
Run npx sass-migrator module --migrate-deps your-entry.scss to convert an entire project. Review output carefully — namespacing changes may break references.
# Automated migration npx sass-migrator module --migrate-deps src/scss/main.scss # Before @import 'variables'; @import 'mixins'; # After @use 'variables'; @use 'mixins';
Comparing Preprocessors
Less uses similar syntax but lacks Sass module system and has a smaller ecosystem. Stylus offers optional syntax but minimal industry adoption. PostCSS is plugin-based, not a full preprocessor.
Sass remains the industry standard for CSS preprocessing in 2024+. Its module system, Dart Sass performance, and framework integration (Bootstrap, Foundation) keep it relevant.
// Sass — industry standard, full-featured
@use 'sass:color';
$adjusted: color.adjust(#2563eb, $lightness: 10%);
// Less — simpler, declining adoption
@primary: #2563eb;
.adjusted { color: lighten(@primary, 10%); }When to Keep Sass
Keep Sass when you rely on: map-driven token generation, complex mixin libraries, framework customization (Bootstrap), or team workflows built around SCSS partials.
Drop Sass when your project only uses variables and nesting — native CSS covers both now. The migration cost should be weighed against maintenance savings. Small projects benefit most from dropping Sass; large design systems often keep it.
- Audit your Sass usage — many projects use less than 20% of features
- CSS nesting, @layer, and custom properties cover 80% of Sass use cases
- Migration tools reduce manual effort but require testing
// Sass still valuable for: // 1. Generating utility classes from maps // 2. Bootstrap/framework variable overrides // 3. Complex responsive mixins // 4. Design token compilation pipelines // Native CSS sufficient for: // 1. Simple variable theming // 2. Basic nesting // 3. Component-scoped styles (CSS Modules)