Writing source that compiles into lean CSS and avoiding the bloat that preprocessors can create if you are not careful.
Why SCSS performance matters
SCSS makes stylesheets easier to write. It can also make them larger if you nest too deep, extend too freely, or generate more CSS than the project needs. The browser only sees the compiled output, so that is what counts.
1. Avoid deep nesting
Three levels is a reasonable limit. Beyond that, selectors get overly specific and the compiled CSS grows.
Example
// Recommended
.navbar {
li {
a {
// Styles
}
}
}
// Avoid
.navbar {
li {
a {
&:hover {
span {
// Overly specific
}
}
}
}
}
2. Be selective with @extend
@extend shares styles between selectors, which sounds efficient. In practice it can create unexpected bloat and specificity tangles. Placeholder selectors (%) are safer than extending regular classes.
Example
%message-shared {
font-size: 1rem;
padding: 10px;
}
.success-message {
@extend %message-shared;
background-color: green;
}
3. Use mixins wisely
Mixins duplicate CSS at every @include call. Fine for small, frequently reused patterns. Problematic for large blocks included dozens of times.
Example
@mixin transition($property, $duration) {
transition: $property $duration;
}
.button {
@include transition(color, 0.3s);
}
4. Watch loops and functions
Loops generate CSS in bulk. Useful for grid systems, but check the output size if you are generating hundreds of utility classes.
Example
@for $i from 1 through 10 {
.text-#{$i} {
font-size: 1rem + ($i * 0.1);
}
}
5. Use variables for repeated values
Variables keep source DRY. They do not reduce compiled CSS size directly, but they make it easier to maintain and refactor without duplication creeping in.
Example
$primary-color: #3498db;
$secondary-color: #2ecc71;
.button {
background-color: $primary-color;
&:hover {
background-color: $secondary-color;
}
}
6. Keep files organised
Partials and imports make it easier to spot what is generating CSS and what is dead weight.
7. Minimise @import overhead
Each @import adds to the compilation. Build tools like Webpack handle dependencies more efficiently for larger projects.
8. Minify and optimise the output
PostCSS with Autoprefixer and cssnano handles prefixing and minification in your build pipeline.
Example: build tool configuration
const postcss = require('gulp-postcss');
const autoprefixer = require('autoprefixer');
const cssnano = require('cssnano');
gulp.task('styles', function () {
var plugins = [
autoprefixer({browsers: ['last 1 version']}),
cssnano()
];
return gulp.src('src/*.scss')
.pipe(sass().on('error', sass.logError))
.pipe(postcss(plugins))
.pipe(gulp.dest('dist'));
});
9. Monitor compiled CSS size
Check the output periodically. CSS Stats and similar tools show file size, selector count, and specificity distribution.
10. Test in browser dev tools
Look for slow selectors, large paint areas, and layout thrashing. Adjust your SCSS based on what the browser actually struggles with.
SCSS is a writing convenience. Performance is about what compiles out the other end. Keep nesting shallow, use @extend sparingly, minify the output, and check the file size before shipping.

