Codeskill

Learn to code, step by step

Optimizing SCSS for Performance: Best Practices

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.

PreviousSCSS and Browser Compatibility: Ensuring Cross-Platform Consistency