SCSS β€’ LEVEL 3 β€’ LESSON 8 OF 9
0% Complete
← Back to Learning Path

⚑ Lesson 8: Performance & Optimization

Make your SCSS grid systems fast, lean, and production-ready!

Why Optimization Matters

SCSS is powerful, but with great power comes great responsibility. Loops and mixins can generate HUGE CSS files if you're not careful. A full 12-column responsive grid system can create 10,000+ lines of CSS!

πŸ’‘ Performance Impact:

Every KB of CSS delays page load. A 500KB CSS file takes ~3 seconds to download on 3G. Optimization isn't optionalβ€”it's essential.

Strategy 1: Generate Only What You Need

Don't generate utilities you won't use:

// ❌ BAD: Generates 12 classes you might not need
@for $i from 1 through 12 {
  .grid-cols-#{$i} {
    grid-template-columns: repeat($i, 1fr);
  }
}

// βœ… GOOD: Only generate what you use
$grid-variations: 1, 2, 3, 4, 6, 12;

@each $cols in $grid-variations {
  .grid-cols-#{$cols} {
    grid-template-columns: repeat($cols, 1fr);
  }
}

Strategy 2: Use PurgeCSS

PurgeCSS removes unused CSS from your compiled files:

// package.json
{
  "scripts": {
    "build:css": "sass styles.scss styles.css",
    "purge:css": "purgecss --css styles.css --content index.html --output styles.min.css"
  }
}

// purgecss.config.js
module.exports = {
  content: [
    './src/**/*.html',
    './src/**/*.js'
  ],
  css: ['./dist/styles.css'],
  safelist: [
    // Classes to never remove
    'grid',
    'grid-cols-1',
    'gap-4'
  ]
}

Strategy 3: Conditional Compilation

// _config.scss
$enable-responsive: true !default;
$enable-gaps: true !default;
$enable-row-utilities: false !default;

// _grid.scss
@if $enable-responsive {
  @each $bp-name, $bp-value in $breakpoints {
    @media (min-width: $bp-value) {
      // Generate responsive classes
    }
  }
}

@if $enable-gaps {
  @each $name, $size in $spacing {
    .gap-#{$name} {
      gap: $size;
    }
  }
}

@if $enable-row-utilities {
  // Only compile if needed
  @for $i from 1 through 6 {
    .row-span-#{$i} {
      grid-row: span $i;
    }
  }
}

Strategy 4: Extend Instead of Duplicate

// ❌ BAD: Duplicates styles
.card-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}

.product-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}

// βœ… GOOD: Share styles with @extend
%grid-base {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}

.card-grid {
  @extend %grid-base;
}

.product-grid {
  @extend %grid-base;
}

// Compiles to:
// .card-grid, .product-grid {
//   display: grid;
//   grid-template-columns: repeat(3, 1fr);
//   gap: 20px;
// }

⚠️ @extend Warning:

Use @extend sparingly! It can create unexpected selector combinations. For utility classes, duplication might be better than complex extends.

Strategy 5: Minification

// Install sass with compression
npm install sass --save-dev

// package.json
{
  "scripts": {
    "build": "sass --style=compressed styles.scss styles.min.css"
  }
}

// Or use PostCSS
{
  "scripts": {
    "build": "sass styles.scss | postcss -u cssnano > styles.min.css"
  }
}

Strategy 6: Smart Breakpoint Generation

// ❌ BAD: Every utility at every breakpoint
@each $bp in (sm, md, lg, xl) {
  @for $i from 1 through 12 {
    .#{$bp}\:col-#{$i} { /* ... */ }
    .#{$bp}\:grid-cols-#{$i} { /* ... */ }
    .#{$bp}\:gap-#{$i} { /* ... */ }
  }
}
// Result: 144+ classes per breakpoint = 576+ classes!

// βœ… GOOD: Only common breakpoint utilities
$responsive-columns: 1, 2, 3, 4;
$responsive-gaps: 2, 4, 6, 8;

@each $bp-name, $bp-value in $breakpoints {
  @media (min-width: $bp-value) {
    @each $col in $responsive-columns {
      .#{$bp-name}\:grid-cols-#{$col} {
        grid-template-columns: repeat($col, 1fr);
      }
    }
    
    @each $gap in $responsive-gaps {
      .#{$bp-name}\:gap-#{$gap} {
        gap: #{$gap * 4}px;
      }
    }
  }
}
// Result: 32 classes total!

Strategy 7: Use CSS Custom Properties

// Instead of generating classes for every value
// Use CSS variables for dynamic values

:root {
  --grid-gap: 20px;
  --grid-columns: 3;
}

.grid {
  display: grid;
  grid-template-columns: repeat(var(--grid-columns), 1fr);
  gap: var(--grid-gap);
}

// Change via inline styles or JavaScript
// 
// No need for .grid-cols-1, .grid-cols-2, etc!

βœ… Best Practice:

Use SCSS variables for compile-time values (breakpoints, spacing scale). Use CSS custom properties for runtime values (theme colors, dynamic spacing).

Strategy 8: Code Splitting

// Split your grid system into modules
// Import only what each page needs

// critical.scss - Inline in 
@import 'config';
@import 'grid-base';        // .grid, basic utilities
@import 'grid-responsive';  // Mobile-first responsive

// non-critical.scss - Load async
@import 'grid-advanced';    // Complex patterns
@import 'grid-animations';  // Transitions
@import 'grid-print';       // Print styles

Optimization Checklist

Measuring Performance

// Check compiled size
sass styles.scss styles.css
ls -lh styles.css

// Before compression: 245KB
// After compression: 45KB
// After PurgeCSS: 12KB

// Analyze what's taking space
npm install -g css-analyzer
css-analyzer styles.css

Real-World Example

// Optimized grid system configuration
// _config.scss

// Only enable what you need
$enable-responsive-grids: true;
$enable-responsive-gaps: true;
$enable-row-utilities: false;    // Disabled - not used
$enable-grid-areas: false;        // Disabled - not used
$enable-auto-fit: true;

// Limited column variations
$grid-columns: (1, 2, 3, 4, 6, 12);  // Not 1-12!

// Limited spacing
$spacing-values: (0, 4, 8, 16, 24, 32, 48);  // Common values only

// Limit responsive utilities
$responsive-breakpoints: (md, lg);  // Skip sm, xl if not needed

// Result: 80% smaller CSS file!

Production Build Script

// package.json
{
  "scripts": {
    "dev": "sass --watch styles.scss:styles.css",
    "build": "sass --style=compressed styles.scss:dist/styles.css && purgecss --css dist/styles.css --content src/**/*.html --output dist/",
    "analyze": "ls -lh dist/styles.css && css-analyzer dist/styles.css"
  }
}

πŸ“ Quick Check (3 Questions)

1. What's the biggest performance issue with SCSS grid systems?

2. What's the best solution for removing unused CSS?

3. When should you use CSS custom properties vs SCSS variables?

← Previous Lesson