Skip to main content

Course Progress

Loading...

CSS Preprocessors Overview (SASS/SCSS)

Duration: 30 minutes
Module 1: CSS Basics

Learning Objectives

  • Master CSS styling techniques
  • Control visual presentation
  • Create attractive designs
  • Understand CSS best practices

What Are CSS Preprocessors?

CSS preprocessors are scripting languages that extend the capabilities of standard CSS, allowing you to write more maintainable, reusable, and organized code. Think of CSS preprocessors as the difference between using a basic calculator versus a scientific calculator—both can add numbers, but one offers powerful features that make complex operations simpler.

The Problem With Native CSS

While CSS is powerful, it has limitations when building large-scale websites:

  • No Variables: In standard CSS, you must repeat values like colors and font sizes throughout your stylesheets
  • No Nesting: Selectors can't be nested, resulting in repetitive, verbose code
  • No Modularity: It's difficult to split your CSS across multiple files without impacting performance
  • Limited Calculations: Performing calculations for values like widths and padding is cumbersome
  • No Functions: You can't create reusable code blocks for common patterns

CSS preprocessors solve these problems by providing programming-like features that compile down to standard CSS that browsers can understand.

CSS Preprocessor Workflow

flowchart LR
    A["Preprocessor Files
.scss, .less, .styl"] --> B["Preprocessor
Compiler"] B --> C["Standard CSS"] C --> D["Browser Rendering"] style A fill:#e6f3ff,stroke:#333,stroke-width:2px style B fill:#f9f,stroke:#333,stroke-width:3px style C fill:#bbf,stroke:#333,stroke-width:2px style D fill:#e6ffe6,stroke:#333,stroke-width:2px

Popular CSS Preprocessors

Feature SASS/SCSS LESS Stylus PostCSS
Syntax SASS: Indented
SCSS: CSS-like
CSS-like Flexible, whitespace-sensitive CSS with plugins
Variables $variable @variable variable = With plugins
Adoption Very High Medium Low High
Learning Curve Moderate Easy Moderate Depends on plugins
Language Type Ruby-based JavaScript-based JavaScript-based JavaScript-based

For this lecture, we'll focus on SASS/SCSS as it's the most widely adopted CSS preprocessor and is commonly used in WordPress theme development.

SASS/SCSS: The Most Popular CSS Preprocessor

SASS (Syntactically Awesome Style Sheets) is a scripting language that compiles to CSS. It exists in two syntaxes: the original indented syntax (SASS) and the newer SCSS (Sassy CSS) syntax. SCSS is CSS-compatible, meaning any valid CSS is also valid SCSS.

SASS vs SCSS Syntax

SASS (Indented Syntax)

// SASS syntax
$primary-color: #3a86ff
$secondary-color: #ff006e

.container
  width: 100%
  max-width: 1200px
  margin: 0 auto
  
  .header
    background-color: $primary-color
    color: white
    padding: 20px
    
    h1
      font-size: 2em
      margin: 0

SCSS (Sassy CSS Syntax)

// SCSS syntax
$primary-color: #3a86ff;
$secondary-color: #ff006e;

.container {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
  
  .header {
    background-color: $primary-color;
    color: white;
    padding: 20px;
    
    h1 {
      font-size: 2em;
      margin: 0;
    }
  }
}

SCSS is the more popular syntax today because:

  • It looks like standard CSS, making the learning curve easier
  • You can copy/paste existing CSS into SCSS files
  • Its syntax aligns better with other programming languages

We'll use SCSS syntax throughout this lecture, but the concepts apply to both formats.

Brief History

  • 2006: Hampton Catlin designed SASS as a markup language preprocessor
  • 2010: SCSS syntax was introduced in SASS 3, making adoption easier
  • 2012: Integration with popular frameworks like Compass began
  • 2014: LibSass emerged, allowing compilation in languages beyond Ruby
  • 2016: SASS became an integral part of most front-end build systems
  • 2020: Dart Sass became the primary implementation, replacing Ruby Sass

Core SASS Features

SASS provides several powerful features that extend CSS's capabilities, allowing you to write more efficient, maintainable code.

Variables

Variables allow you to store information that you can reuse throughout your stylesheet. Think of variables as storage containers for values that you'll use repeatedly.

Basic Variable Usage

// Variables in SCSS
$primary-color: #3a86ff;
$secondary-color: #ff006e;
$base-font-size: 16px;
$heading-font: 'Montserrat', sans-serif;
$body-font: 'Open Sans', sans-serif;
$spacing-unit: 8px;

// Using variables
body {
  font-family: $body-font;
  font-size: $base-font-size;
  line-height: 1.6;
}

h1, h2, h3, h4, h5, h6 {
  font-family: $heading-font;
  color: $primary-color;
  margin-bottom: $spacing-unit * 3; // 24px
}

.button {
  background-color: $secondary-color;
  padding: $spacing-unit * 2;  // 16px
  color: white;
  border-radius: 4px;
}

Advantages of Variables

  • Central Management: Update values in one place
  • Consistency: Ensure the same values are used throughout
  • Meaningful Names: Use descriptive names instead of cryptic values
  • Calculations: Perform operations using variables

Real-World Example: Theme Color System

// Define brand colors
$brand-primary: #3a86ff;
$brand-secondary: #ff006e;
$brand-tertiary: #ffbe0b;

// Create color variations
$brand-primary-light: lighten($brand-primary, 15%);
$brand-primary-dark: darken($brand-primary, 15%);
$brand-secondary-light: lighten($brand-secondary, 15%);
$brand-secondary-dark: darken($brand-secondary, 15%);

// Text colors based on background
$text-on-dark: white;
$text-on-light: #333;

// Usage in components
.header {
  background-color: $brand-primary;
  color: $text-on-dark;
}

.footer {
  background-color: $brand-primary-dark;
  color: $text-on-dark;
}

.button-primary {
  background-color: $brand-primary;
  color: $text-on-dark;
  
  &:hover {
    background-color: $brand-primary-dark;
  }
}

.button-secondary {
  background-color: $brand-secondary;
  color: $text-on-dark;
  
  &:hover {
    background-color: $brand-secondary-dark;
  }
}

WordPress Theme Integration

Variables are perfect for WordPress themes as they allow for easy customization:

// _variables.scss
// Theme colors - can be easily modified for different theme versions
$theme-primary: #3a86ff;
$theme-secondary: #ff006e;
$theme-background: #f9f9f9;
$theme-text: #333333;

// WordPress-specific spacing
$wp-admin-bar-height: 32px;
$content-width: 960px;
$sidebar-width: 300px;

// Breakpoints aligned with WordPress content width
$breakpoint-small: 600px;    // Mobile devices
$breakpoint-medium: 960px;   // Tablets & small desktops
$breakpoint-large: 1280px;   // Desktops

Nesting

Nesting allows you to write selectors inside other selectors, creating a visual hierarchy that matches your HTML structure. It's like organizing a filing cabinet with folders and subfolders.

Basic Nesting

SCSS
nav {
  background-color: #333;
  
  ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }
  
  li {
    display: inline-block;
    
    a {
      display: block;
      padding: 10px 15px;
      color: white;
      text-decoration: none;
      
      &:hover {
        background-color: #555;
      }
    }
  }
}
Compiled CSS
nav {
  background-color: #333;
}
nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
}
nav li {
  display: inline-block;
}
nav li a {
  display: block;
  padding: 10px 15px;
  color: white;
  text-decoration: none;
}
nav li a:hover {
  background-color: #555;
}

Advanced Nesting with Parent Selector

The & symbol is a special character that refers to the parent selector. It's useful for creating pseudo-classes, modifiers, and more.

.button {
  background-color: #3a86ff;
  color: white;
  padding: 10px 20px;
  border-radius: 4px;
  
  // Pseudo-classes
  &:hover {
    background-color: darken(#3a86ff, 10%);
  }
  
  &:focus {
    outline: 2px solid rgba(58, 134, 255, 0.5);
  }
  
  // Modifiers using BEM naming convention
  &--large {
    padding: 15px 30px;
    font-size: 1.2em;
  }
  
  &--small {
    padding: 5px 10px;
    font-size: 0.8em;
  }
  
  // Parent states affecting child elements
  .disabled & {
    opacity: 0.5;
    cursor: not-allowed;
  }
  
  // Media queries
  @media (max-width: 768px) {
    display: block;
    width: 100%;
  }
}

This compiles to:

.button {
  background-color: #3a86ff;
  color: white;
  padding: 10px 20px;
  border-radius: 4px;
}
.button:hover {
  background-color: #0065f2;
}
.button:focus {
  outline: 2px solid rgba(58, 134, 255, 0.5);
}
.button--large {
  padding: 15px 30px;
  font-size: 1.2em;
}
.button--small {
  padding: 5px 10px;
  font-size: 0.8em;
}
.disabled .button {
  opacity: 0.5;
  cursor: not-allowed;
}
@media (max-width: 768px) {
  .button {
    display: block;
    width: 100%;
  }
}

Nesting Warning

While nesting is powerful, excessive nesting can lead to several problems:

  • Specificity Issues: Deeply nested selectors create highly specific CSS rules
  • Overly Coupled Code: Styles become tightly coupled to HTML structure
  • Difficult Maintenance: Deep nesting can make styles harder to update
  • Larger Output: Deeply nested selectors create larger CSS files

Best practice: Limit nesting to 3 levels deep when possible.

WordPress Integration Example

// WordPress comment styling with nesting
.comments-area {
  margin-top: 40px;
  border-top: 1px solid #eee;
  
  .comments-title {
    font-size: 24px;
    margin-bottom: 20px;
  }
  
  .comment-list {
    list-style: none;
    padding: 0;
    
    .comment {
      padding: 20px 0;
      border-bottom: 1px solid #eee;
      
      .comment-author {
        display: flex;
        align-items: center;
        
        .avatar {
          margin-right: 15px;
          border-radius: 50%;
        }
        
        .fn {
          font-weight: bold;
        }
      }
      
      .comment-metadata {
        font-size: 12px;
        color: #777;
        margin: 5px 0 15px;
      }
      
      .comment-content {
        p {
          margin-bottom: 15px;
        }
      }
      
      .reply {
        margin-top: 10px;
        
        a {
          color: #3a86ff;
          text-decoration: none;
          
          &:hover {
            text-decoration: underline;
          }
        }
      }
      
      // Nested comments (replies)
      .children {
        list-style: none;
        padding-left: 40px;
        margin-top: 20px;
      }
    }
  }
}

Partials and Imports

Partials are smaller SCSS files that you can include in other SCSS files. This feature allows you to modularize your CSS and organize it into smaller, more maintainable chunks.

How Partials Work

Partials use a naming convention with a leading underscore (e.g., _variables.scss). The underscore tells SASS not to compile this file into a separate CSS file.

You can then import these partials into your main SCSS file using the @import directive.

File Structure Example
scss/
 ├── main.scss
 ├── _variables.scss
 ├── _typography.scss
 ├── _buttons.scss
 ├── _forms.scss
 └── _layout.scss
main.scss
// Import partials
@import 'variables';
@import 'typography';
@import 'buttons';
@import 'forms';
@import 'layout';

// Additional styles...
body {
  background-color: $bg-color;
}

Advantages of Partials

  • Organization: Split CSS into logical components
  • Maintainability: Easier to locate and update specific styles
  • Team Collaboration: Different team members can work on different files
  • Performance: Compiles into a single CSS file, avoiding multiple HTTP requests
  • Reusability: Import only what you need in specific contexts

WordPress Theme Partials Structure

scss/
 ├── main.scss               /* Main file for importing all others */
 ├── abstracts/
 │   ├── _variables.scss     /* Theme variables */
 │   ├── _functions.scss     /* Custom functions */
 │   ├── _mixins.scss        /* Reusable mixins */
 │   └── _placeholders.scss  /* Extend placeholders */
 ├── base/
 │   ├── _reset.scss         /* CSS reset/normalize */
 │   ├── _typography.scss    /* Typography styles */
 │   └── _helpers.scss       /* Helper classes */
 ├── components/
 │   ├── _buttons.scss       /* Button styles */
 │   ├── _navigation.scss    /* Navigation menus */
 │   ├── _sidebar.scss       /* Sidebar styles */
 │   ├── _forms.scss         /* Form elements */
 │   └── _widgets.scss       /* WordPress widgets */
 ├── layouts/
 │   ├── _header.scss        /* Header styles */
 │   ├── _footer.scss        /* Footer styles */
 │   ├── _grid.scss          /* Grid system */
 │   └── _blog.scss          /* Blog layout */
 ├── pages/
 │   ├── _home.scss          /* Homepage styles */
 │   ├── _about.scss         /* About page */
 │   └── _contact.scss       /* Contact page */
 ├── plugins/
 │   ├── _woocommerce.scss   /* WooCommerce styles */
 │   └── _acf.scss           /* Advanced Custom Fields styles */
 └── admin/
     └── _editor.scss        /* Gutenberg editor styles */

The main.scss file would import all these partials in the proper order:

/*!
Theme Name: My WordPress Theme
Theme URI: https://example.com/my-theme
Author: Your Name
Description: A custom WordPress theme
Version: 1.0.0
License: GNU General Public License v2 or later
*/

// Abstracts
@import 'abstracts/variables';
@import 'abstracts/functions';
@import 'abstracts/mixins';
@import 'abstracts/placeholders';

// Base
@import 'base/reset';
@import 'base/typography';
@import 'base/helpers';

// Layouts
@import 'layouts/grid';
@import 'layouts/header';
@import 'layouts/footer';
@import 'layouts/blog';

// Components
@import 'components/buttons';
@import 'components/navigation';
@import 'components/sidebar';
@import 'components/forms';
@import 'components/widgets';

// Pages
@import 'pages/home';
@import 'pages/about';
@import 'pages/contact';

// Plugins
@import 'plugins/woocommerce';
@import 'plugins/acf';

Mixins

Mixins allow you to define reusable blocks of CSS that you can include in other rules. Think of them as functions in programming languages that accept parameters and return a set of styles.

Basic Mixin Usage

// Defining a mixin
@mixin border-radius($radius) {
  -webkit-border-radius: $radius;
     -moz-border-radius: $radius;
          border-radius: $radius;
}

// Using the mixin
.button {
  @include border-radius(5px);
}

.avatar {
  @include border-radius(50%);
}

This compiles to:

.button {
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
  border-radius: 5px;
}

.avatar {
  -webkit-border-radius: 50%;
  -moz-border-radius: 50%;
  border-radius: 50%;
}

Advanced Mixins

Mixins can include default parameters, conditional logic, and even other mixins:

// Mixin with default values and logic
@mixin button-style($bg-color: #3a86ff, $text-color: white, $padding: 10px) {
  display: inline-block;
  background-color: $bg-color;
  color: $text-color;
  padding: $padding $padding * 2;
  border: none;
  border-radius: 4px;
  text-decoration: none;
  text-align: center;
  cursor: pointer;
  transition: all 0.3s ease;
  
  // Check if background is light and adjust text color
  @if (lightness($bg-color) > 70%) {
    color: #333;
  }
  
  &:hover {
    background-color: darken($bg-color, 10%);
  }
}

// Using the advanced mixin
.button-primary {
  @include button-style(); // Uses defaults
}

.button-secondary {
  @include button-style(#ff006e); // Custom background
}

.button-success {
  @include button-style(#28a745, white, 15px); // All custom values
}

.button-light {
  @include button-style(#f8f9fa); // Light background, dark text
}

Practical Mixins for Responsive Design

// Responsive breakpoints mixin
@mixin respond-to($breakpoint) {
  @if $breakpoint == small {
    @media (max-width: 576px) { @content; }
  } @else if $breakpoint == medium {
    @media (max-width: 768px) { @content; }
  } @else if $breakpoint == large {
    @media (max-width: 992px) { @content; }
  } @else if $breakpoint == xlarge {
    @media (max-width: 1200px) { @content; }
  }
}

// Using the responsive mixin
.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 15px;
  
  @include respond-to(xlarge) {
    max-width: 1140px;
  }
  
  @include respond-to(large) {
    max-width: 960px;
  }
  
  @include respond-to(medium) {
    max-width: 720px;
  }
  
  @include respond-to(small) {
    max-width: 100%;
  }
}

WordPress-Specific Mixins

// WordPress admin bar spacing mixin
@mixin admin-bar-spacing($top: 0) {
  .admin-bar & {
    top: calc(#{$top} + 32px);
    
    @media screen and (max-width: 782px) {
      top: calc(#{$top} + 46px);
    }
  }
}

// WordPress featured image aspect ratio mixin
@mixin featured-image-ratio($width: 16, $height: 9) {
  position: relative;
  overflow: hidden;
  padding-top: percentage($height / $width);
  
  img {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
}

// Usage
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  z-index: 100;
  
  @include admin-bar-spacing();
}

.post-thumbnail {
  @include featured-image-ratio();
  
  // Different ratio for featured posts
  &.featured {
    @include featured-image-ratio(2, 1);
  }
}

Extend/Inheritance

The @extend directive lets you share styles between selectors. It's like inheriting properties in object-oriented programming.

Basic @extend Usage

// Base message style
.message {
  padding: 10px;
  border: 1px solid #ccc;
  color: #333;
}

// Extended styles
.success {
  @extend .message;
  border-color: green;
  color: green;
}

.error {
  @extend .message;
  border-color: red;
  color: red;
}

.warning {
  @extend .message;
  border-color: orange;
  color: orange;
}

This compiles to:

.message, .success, .error, .warning {
  padding: 10px;
  border: 1px solid #ccc;
  color: #333;
}

.success {
  border-color: green;
  color: green;
}

.error {
  border-color: red;
  color: red;
}

.warning {
  border-color: orange;
  color: orange;
}

Placeholder Selectors

Placeholder selectors (using %) are special selectors that only appear in the CSS when extended. They're ideal for creating reusable style patterns.

// Placeholder selector (won't be output to CSS unless extended)
%button-base {
  display: inline-block;
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  font-weight: bold;
  text-decoration: none;
  text-align: center;
  cursor: pointer;
  transition: all 0.3s ease;
}

// Button variations that extend the placeholder
.button-primary {
  @extend %button-base;
  background-color: #3a86ff;
  color: white;
  
  &:hover {
    background-color: darken(#3a86ff, 10%);
  }
}

.button-secondary {
  @extend %button-base;
  background-color: #ff006e;
  color: white;
  
  &:hover {
    background-color: darken(#ff006e, 10%);
  }
}

.button-outline {
  @extend %button-base;
  background-color: transparent;
  border: 2px solid #3a86ff;
  color: #3a86ff;
  
  &:hover {
    background-color: #3a86ff;
    color: white;
  }
}

This compiles to:

.button-primary, .button-secondary, .button-outline {
  display: inline-block;
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  font-weight: bold;
  text-decoration: none;
  text-align: center;
  cursor: pointer;
  transition: all 0.3s ease;
}

.button-primary {
  background-color: #3a86ff;
  color: white;
}
.button-primary:hover {
  background-color: #0065f2;
}

.button-secondary {
  background-color: #ff006e;
  color: white;
}
.button-secondary:hover {
  background-color: #d80058;
}

.button-outline {
  background-color: transparent;
  border: 2px solid #3a86ff;
  color: #3a86ff;
}
.button-outline:hover {
  background-color: #3a86ff;
  color: white;
}

@extend vs @mixin

Both @extend and @mixin help create reusable code, but they work differently:

@extend @mixin
Combines selectors in CSS output Duplicates code in each selector
Results in smaller CSS file size Can result in larger CSS file size
No parameters or arguments Can accept parameters for customization
Maintains relationships in the cascade Each instance is independent
Can lead to complex selectors Creates predictable output

When to use which:

  • Use @extend when:
    • The styles truly represent an "is-a" relationship
    • File size is a concern
    • You don't need to customize the styles with parameters
  • Use @mixin when:
    • You need to pass variables to customize the output
    • You want to avoid long, complex selector chains
    • You need conditional logic in your styles

WordPress Theme Integration

// WordPress-specific placeholders
%entry-meta {
  font-size: 0.875rem;
  color: #666;
  margin-bottom: 1rem;
  
  a {
    color: inherit;
    text-decoration: none;
    
    &:hover {
      color: $primary-color;
    }
  }
}

%block-padding {
  padding: 2rem;
  
  @media (max-width: 768px) {
    padding: 1.5rem;
  }
  
  @media (max-width: 576px) {
    padding: 1rem;
  }
}

// Usage in WordPress templates
.post {
  .entry-meta {
    @extend %entry-meta;
  }
}

.page {
  .entry-meta {
    @extend %entry-meta;
    text-align: center;
  }
}

.widget {
  @extend %block-padding;
  background-color: #f8f9fa;
}

.comment-body {
  @extend %block-padding;
  border: 1px solid #eee;
}

Functions and Operators

SASS provides built-in functions and allows you to perform operations on values. This gives you the power to calculate and manipulate values dynamically.

Built-in Functions

SASS includes numerous functions for working with colors, strings, numbers, and more:

Color Functions
// Color manipulation
$base-color: #3a86ff;

.light-variation {
  // Lighten - makes a color lighter
  color: lighten($base-color, 20%);  // #9dbdff
}

.dark-variation {
  // Darken - makes a color darker
  color: darken($base-color, 20%);   // #004cb3
}

.desaturated {
  // Desaturate - reduces color saturation
  color: desaturate($base-color, 30%);  // #5379d6
}

.transparent {
  // Rgba - adds transparency
  background-color: rgba($base-color, 0.5);  // rgba(58, 134, 255, 0.5)
}

.complement {
  // Complement - gets the opposite color on the color wheel
  color: complement($base-color);  // #ff973a
}
Math Functions
// Math operations
$width: 100%;
$columns: 12;
$margin: 2%;

.column {
  width: ($width / $columns) - ($margin * 2);  // 4.33%
  
  &.span-2 {
    // Round - rounds to the nearest whole number
    width: round(($width / ($columns / 2)) - ($margin * 2));  // 46%
  }
  
  &.span-3 {
    // Floor - rounds down
    width: floor(($width / ($columns / 3)) - ($margin * 2));  // 29%
  }
  
  &.span-4 {
    // Ceil - rounds up
    width: ceil(($width / ($columns / 4)) - ($margin * 2));  // 30%
  }
}
String Functions
// String manipulation
$theme-name: "bootstrap";
$version: 5;

.theme-info {
  // To-upper-case - converts to uppercase
  content: to-upper-case($theme-name);  // "BOOTSTRAP"
  
  // Str-length - gets string length
  font-size: str-length($theme-name) * 1px;  // 9px
  
  // String interpolation
  font-family: "#{$theme-name}-v#{$version}";  // "bootstrap-v5"
}
List Functions
// List operations
$social-colors: (facebook: #3b5998, twitter: #1da1f2, instagram: #e1306c);
$spacing-sizes: 0 5px 10px 15px 20px;

.social-icon {
  // Map-get - retrieves value from a map
  &.facebook { color: map-get($social-colors, facebook); }  // #3b5998
  &.twitter { color: map-get($social-colors, twitter); }    // #1da1f2
  
  // Nth - retrieves value at position
  padding: nth($spacing-sizes, 3);  // 10px
  
  // Length - gets list length
  z-index: length($spacing-sizes);  // 5
}

Custom Functions

You can create your own functions with @function to perform specific calculations:

// Pixels to REMs converter
@function rem($pixels, $context: 16) {
  @return #{$pixels / $context}rem;
}

// Z-index management
$z-layers: (
  modal: 9000,
  overlay: 8000,
  dropdown: 7000,
  header: 6000,
  footer: 5000
);

@function z($layer) {
  @if not map-has-key($z-layers, $layer) {
    @error "No z-index found for `#{$layer}` in $z-layers map.";
  }
  
  @return map-get($z-layers, $layer);
}

// Color contrast checker and adjustor
@function color-contrast($color) {
  $luminance: 0.2126 * red($color) + 0.7152 * green($color) + 0.0722 * blue($color);
  
  @return if($luminance > 165, #333, #fff);
}

// Usage
body {
  font-size: rem(16);  // 1rem
}

h1 {
  font-size: rem(32);  // 2rem
  margin-bottom: rem(24);  // 1.5rem
}

.modal {
  z-index: z(modal);  // 9000
}

.header {
  z-index: z(header);  // 6000
}

.button {
  background-color: #3a86ff;
  color: color-contrast(#3a86ff);  // white
}

WordPress Grid System Function

// WordPress-specific column calculator
$content-width: 1200px;
$gutter: 30px;

@function col-width($columns, $total-columns: 12) {
  @return calc((#{$content-width} - (#{$total-columns - 1} * #{$gutter})) / #{$total-columns} * #{$columns} + (#{$columns - 1} * #{$gutter}));
}

// WordPress layout with custom grid functions
.site-content {
  max-width: $content-width;
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  gap: $gutter;
}

.content-area {
  width: col-width(8);  // Main content area
  
  @media (max-width: 768px) {
    width: 100%;
  }
}

.widget-area {
  width: col-width(4);  // Sidebar
  
  @media (max-width: 768px) {
    width: 100%;
  }
}

// Footer widgets
.footer-widgets {
  display: flex;
  flex-wrap: wrap;
  gap: $gutter;
  
  .widget {
    width: col-width(3);
    
    @media (max-width: 992px) {
      width: col-width(6);
    }
    
    @media (max-width: 576px) {
      width: 100%;
    }
  }
}

Control Directives

SASS includes control directives like @if, @for, @each, and @while that allow you to create complex, dynamic styles with programmatic logic.

Conditional Logic with @if

// Theme mode variable
$theme-mode: 'light';  // or 'dark'

// Conditional styling based on theme mode
body {
  @if $theme-mode == 'light' {
    background-color: #fff;
    color: #333;
  } @else if $theme-mode == 'dark' {
    background-color: #222;
    color: #f5f5f5;
  } @else {
    // Fallback
    background-color: #f8f9fa;
    color: #333;
  }
}

// Function with conditional logic
@function text-color($bg-color) {
  @if (lightness($bg-color) > 60%) {
    @return #333;  // Dark text for light backgrounds
  } @else {
    @return #fff;  // Light text for dark backgrounds
  }
}

// Usage
.card {
  background-color: #f8f9fa;
  color: text-color(#f8f9fa);  // #333
}

.button-primary {
  background-color: #3a86ff;
  color: text-color(#3a86ff);  // #fff
}

Loops with @for, @each, and @while

// @for loop for generating grid classes
@for $i from 1 through 12 {
  .col-#{$i} {
    width: percentage($i / 12);
  }
}

// @each loop for iterating over a list or map
$theme-colors: (
  'primary': #3a86ff,
  'secondary': #ff006e,
  'success': #28a745,
  'warning': #ffc107,
  'danger': #dc3545
);

@each $name, $color in $theme-colors {
  .bg-#{$name} {
    background-color: $color;
    color: text-color($color);
  }
  
  .text-#{$name} {
    color: $color;
  }
  
  .border-#{$name} {
    border-color: $color;
  }
}

// @while loop example
$opacity: 1;

@while $opacity > 0 {
  .opacity-#{$opacity * 100} {
    opacity: $opacity;
  }
  
  $opacity: $opacity - 0.2;
}

WordPress Theme Integration with Control Directives

// WordPress-specific control directives

// Generate admin color scheme classes
$admin-colors: (
  'blue': #2271b1,
  'coffee': #c7a589,
  'ectoplasm': #523f6d,
  'midnight': #363b3f,
  'ocean': #738e96,
  'sunrise': #cf4944
);

@each $name, $primary in $admin-colors {
  .admin-color-#{$name} {
    // Admin bar style
    #wpadminbar {
      background-color: $primary;
    }
    
    // Admin menu style
    #adminmenu,
    #adminmenu .wp-submenu,
    #adminmenuback,
    #adminmenuwrap {
      background-color: darken($primary, 10%);
    }
  }
}

// Generate editor block spacing classes
$spacings: (
  'tiny': 0.5rem,
  'small': 1rem,
  'medium': 2rem,
  'large': 3rem,
  'huge': 5rem
);

@each $name, $size in $spacings {
  .has-#{$name}-spacing {
    margin-bottom: $size;
  }
  
  .has-#{$name}-padding {
    padding: $size;
  }
}

// Generate responsive visibility classes
$breakpoints: (
  'small': 576px,
  'medium': 768px,
  'large': 992px,
  'xlarge': 1200px
);

@each $name, $width in $breakpoints {
  @media (max-width: $width) {
    .hide-on-#{$name} {
      display: none !important;
    }
  }
  
  @media (min-width: $width) {
    .show-on-#{$name} {
      display: block !important;
    }
  }
}

Integrating SASS into WordPress Development

Now that we understand the core SASS features, let's explore how to integrate SASS into WordPress theme development workflow.

Setting Up Your Development Environment

Installing Node.js and NPM

Most modern WordPress theme development uses Node.js and NPM to manage dependencies and build processes. Here's how to set it up:

  1. Download and install Node.js from nodejs.org
  2. Open your terminal/command prompt and verify installation:
    node -v
    npm -v
  3. Navigate to your WordPress theme folder:
    cd /path/to/wordpress/wp-content/themes/your-theme
  4. Initialize a new NPM project:
    npm init -y

Installing SASS and Build Tools

# Install development dependencies
npm install --save-dev sass node-sass gulp gulp-sass gulp-postcss autoprefixer cssnano gulp-sourcemaps gulp-rename browser-sync

These packages serve the following purposes:

  • sass/node-sass: Compile SCSS to CSS
  • gulp: Task runner for automation
  • gulp-sass: Gulp plugin for SASS
  • gulp-postcss: Gulp plugin for PostCSS
  • autoprefixer: Adds vendor prefixes automatically
  • cssnano: Minifies CSS output
  • gulp-sourcemaps: Generates sourcemaps for debugging
  • gulp-rename: Renames output files
  • browser-sync: Live reloading for development

Creating a Gulp Configuration

Create a file named gulpfile.js in your theme's root directory:

// gulpfile.js
const gulp = require('gulp');
const sass = require('gulp-sass')(require('sass'));
const postcss = require('gulp-postcss');
const autoprefixer = require('autoprefixer');
const cssnano = require('cssnano');
const sourcemaps = require('gulp-sourcemaps');
const rename = require('gulp-rename');
const browserSync = require('browser-sync').create();

// Define file paths
const paths = {
  styles: {
    src: './sass/**/*.scss',
    dest: './assets/css'
  },
  php: {
    src: './**/*.php'
  }
};

// Compile SASS
function styles() {
  return gulp.src(paths.styles.src)
    .pipe(sourcemaps.init())
    .pipe(sass().on('error', sass.logError))
    .pipe(postcss([
      autoprefixer(),
      cssnano()
    ]))
    .pipe(rename({
      suffix: '.min'
    }))
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest(paths.styles.dest))
    .pipe(browserSync.stream());
}

// Watch for changes
function watch() {
  browserSync.init({
    proxy: 'localhost/wordpress', // Change to your local development URL
    notify: false
  });
  
  gulp.watch(paths.styles.src, styles);
  gulp.watch(paths.php.src).on('change', browserSync.reload);
}

// Define tasks
exports.styles = styles;
exports.watch = watch;
exports.default = gulp.series(styles, watch);

WordPress Theme Folder Structure with SASS

your-theme/
 ├── assets/
 │   ├── css/
 │   │   └── main.min.css     /* Compiled and minified CSS */
 │   ├── js/
 │   └── images/
 ├── inc/                     /* Theme functions and features */
 ├── sass/                    /* SASS source files */
 │   ├── abstracts/
 │   ├── base/
 │   ├── components/
 │   ├── layouts/
 │   ├── pages/
 │   └── main.scss            /* Main SASS file */
 ├── template-parts/          /* Reusable template parts */
 ├── functions.php            /* Theme functions */
 ├── index.php                /* Main template */
 ├── style.css                /* Theme information */
 ├── package.json             /* NPM configuration */
 └── gulpfile.js              /* Gulp configuration */

Real-World WordPress Theme SCSS Structure

Abstracts Folder

The abstracts folder contains all SASS tools and helpers used across the project. These files don't output any CSS when compiled.

sass/abstracts/
 ├── _variables.scss          /* Global variables */
 ├── _functions.scss          /* Custom functions */
 ├── _mixins.scss             /* Reusable mixins */
 └── _placeholders.scss       /* Placeholder selectors */
Example _variables.scss
// Theme identity
$theme-name: 'my-theme';
$theme-version: '1.0.0';

// Colors
$color-primary: #3a86ff;
$color-secondary: #ff006e;
$color-accent: #ffbe0b;

$color-success: #28a745;
$color-warning: #ffc107;
$color-danger: #dc3545;
$color-info: #17a2b8;

$color-dark: #333333;
$color-light: #f8f9fa;
$color-gray: #6c757d;

$body-bg: white;
$body-color: $color-dark;
$link-color: $color-primary;
$link-hover-color: darken($color-primary, 15%);

// Typography
$font-family-base: 'Open Sans', -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
$font-family-heading: 'Montserrat', $font-family-base;

$font-size-base: 16px;
$line-height-base: 1.6;

// Spacing
$spacer: 1rem;
$spacers: (
  0: 0,
  1: $spacer * 0.25,  // 4px
  2: $spacer * 0.5,   // 8px
  3: $spacer,         // 16px
  4: $spacer * 1.5,   // 24px
  5: $spacer * 3      // 48px
);

// Container
$container-max-width: 1200px;
$grid-gutter-width: 30px;

// WordPress specific
$content-width: 800px;
$sidebar-width: 300px;

// Breakpoints
$breakpoints: (
  xs: 0,
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px
);

// Z-index
$z-indices: (
  dropdown: 1000,
  sticky: 1020,
  fixed: 1030,
  modal-backdrop: 1040,
  modal: 1050,
  popover: 1060,
  tooltip: 1070
);
Example _mixins.scss
// Responsive breakpoints mixin
@mixin breakpoint($point) {
  @if map-has-key($breakpoints, $point) {
    @media (min-width: map-get($breakpoints, $point)) {
      @content;
    }
  } @else {
    @media (min-width: $point) {
      @content;
    }
  }
}

// Clearfix mixin
@mixin clearfix() {
  &::after {
    display: block;
    content: "";
    clear: both;
  }
}

// Visually hidden but accessible content
@mixin visually-hidden() {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

// WordPress admin bar spacing
@mixin admin-bar-padding($top: 0) {
  .admin-bar & {
    padding-top: $top + 32px;
    
    @media screen and (max-width: 782px) {
      padding-top: $top + 46px;
    }
  }
}

Base Folder

The base folder contains the boilerplate code for the project. Here you'll find reset files, typography rules, and foundational styles.

sass/base/
 ├── _reset.scss           /* CSS reset/normalize */
 ├── _typography.scss      /* Typography rules */
 ├── _forms.scss           /* Base form styles */
 └── _accessibility.scss   /* WordPress accessibility */
Example _typography.scss
// Base typography styles
body {
  font-family: $font-family-base;
  font-size: $font-size-base;
  line-height: $line-height-base;
  color: $body-color;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

// Headings
h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
  font-family: $font-family-heading;
  font-weight: 700;
  line-height: 1.2;
  margin-top: 0;
  margin-bottom: $spacer;
  color: $color-dark;
}

h1, .h1 { font-size: $font-size-base * 2.5; }  // 40px
h2, .h2 { font-size: $font-size-base * 2; }    // 32px
h3, .h3 { font-size: $font-size-base * 1.75; } // 28px
h4, .h4 { font-size: $font-size-base * 1.5; }  // 24px
h5, .h5 { font-size: $font-size-base * 1.25; } // 20px
h6, .h6 { font-size: $font-size-base; }        // 16px

// Responsive heading sizes
@include breakpoint(md) {
  h1, .h1 { font-size: $font-size-base * 3; }     // 48px
  h2, .h2 { font-size: $font-size-base * 2.5; }   // 40px
  h3, .h3 { font-size: $font-size-base * 2; }     // 32px
  h4, .h4 { font-size: $font-size-base * 1.75; }  // 28px
  h5, .h5 { font-size: $font-size-base * 1.5; }   // 24px
  h6, .h6 { font-size: $font-size-base * 1.25; }  // 20px
}

// Links
a {
  color: $link-color;
  text-decoration: none;
  transition: color 0.3s ease;
  
  &:hover {
    color: $link-hover-color;
    text-decoration: underline;
  }
}

// Paragraphs
p {
  margin-top: 0;
  margin-bottom: $spacer;
}

// Lists
ul, ol {
  margin-top: 0;
  margin-bottom: $spacer;
  padding-left: $spacer * 2;
}

// Blockquotes
blockquote {
  margin: 0 0 $spacer;
  padding: $spacer;
  border-left: 4px solid $color-primary;
  background-color: rgba($color-primary, 0.05);
  
  p {
    margin-bottom: 0;
  }
  
  cite {
    display: block;
    margin-top: $spacer * 0.5;
    font-size: 0.875em;
    color: $color-gray;
  }
}

// Code
pre, code {
  font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
}

code {
  padding: 0.2em 0.4em;
  font-size: 0.875em;
  background-color: rgba($color-gray, 0.1);
  border-radius: 3px;
}

pre {
  padding: $spacer;
  margin-top: 0;
  margin-bottom: $spacer;
  overflow: auto;
  background-color: $color-light;
  border-radius: 4px;
  
  code {
    padding: 0;
    background-color: transparent;
  }
}

Components Folder

The components folder contains all reusable UI components, such as buttons, forms, navigation, etc.

sass/components/
 ├── _buttons.scss         /* Button styles */
 ├── _card.scss            /* Card component */
 ├── _navigation.scss      /* Navigation menus */
 ├── _pagination.scss      /* Pagination styles */
 ├── _comments.scss        /* WordPress comments */
 └── _widgets.scss         /* WordPress widgets */
Example _buttons.scss
// Base button styles
.btn,
button,
input[type="button"],
input[type="reset"],
input[type="submit"] {
  display: inline-block;
  padding: $spacer * 0.5 $spacer;
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.5;
  text-align: center;
  text-decoration: none;
  color: $color-light;
  background-color: $color-primary;
  border: 1px solid transparent;
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.3s ease;
  
  &:hover, &:focus {
    background-color: darken($color-primary, 10%);
    text-decoration: none;
    color: $color-light;
  }
  
  &:focus {
    outline: 4px solid rgba($color-primary, 0.25);
    outline-offset: 1px;
  }
  
  &:active {
    transform: translateY(1px);
  }
  
  &:disabled, &.disabled {
    opacity: 0.65;
    cursor: not-allowed;
  }
}

// Button variations
.btn-secondary {
  background-color: $color-secondary;
  
  &:hover, &:focus {
    background-color: darken($color-secondary, 10%);
  }
  
  &:focus {
    outline-color: rgba($color-secondary, 0.25);
  }
}

.btn-success {
  background-color: $color-success;
  
  &:hover, &:focus {
    background-color: darken($color-success, 10%);
  }
  
  &:focus {
    outline-color: rgba($color-success, 0.25);
  }
}

.btn-outline {
  color: $color-primary;
  background-color: transparent;
  border-color: $color-primary;
  
  &:hover, &:focus {
    color: $color-light;
    background-color: $color-primary;
  }
}

// Button sizes
.btn-lg {
  padding: $spacer * 0.75 $spacer * 1.5;
  font-size: 1.25rem;
}

.btn-sm {
  padding: $spacer * 0.25 $spacer * 0.5;
  font-size: 0.875rem;
}

// Full width button
.btn-block {
  display: block;
  width: 100%;
}
Example _navigation.scss
// Main navigation
.main-navigation {
  display: flex;
  align-items: center;
  
  .menu {
    display: flex;
    list-style: none;
    margin: 0;
    padding: 0;
  }
  
  .menu-item {
    position: relative;
    
    a {
      display: block;
      padding: $spacer * 0.5 $spacer;
      color: $color-dark;
      text-decoration: none;
      transition: color 0.3s ease;
      
      &:hover {
        color: $color-primary;
      }
    }
    
    &.current-menu-item > a {
      color: $color-primary;
      font-weight: 600;
    }
  }
  
  // Sub-menu (dropdown)
  .sub-menu {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    min-width: 200px;
    background-color: $color-light;
    border: 1px solid rgba(0, 0, 0, 0.1);
    border-radius: 4px;
    padding: $spacer * 0.5;
    z-index: map-get($z-indices, dropdown);
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
    
    .menu-item {
      width: 100%;
      
      a {
        padding: $spacer * 0.5;
      }
    }
  }
  
  .menu-item-has-children {
    &:hover > .sub-menu {
      display: block;
    }
    
    > a {
      &::after {
        content: "";
        display: inline-block;
        width: 0;
        height: 0;
        margin-left: $spacer * 0.5;
        border-top: 4px solid currentColor;
        border-right: 4px solid transparent;
        border-left: 4px solid transparent;
        vertical-align: middle;
      }
    }
  }
  
  // Mobile navigation
  @media (max-width: map-get($breakpoints, md)) {
    .menu {
      display: none;
      
      &.toggled {
        display: flex;
        flex-direction: column;
        position: absolute;
        top: 100%;
        left: 0;
        width: 100%;
        background-color: $color-light;
        padding: $spacer;
        border-top: 1px solid rgba(0, 0, 0, 0.1);
        box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
      }
    }
    
    .menu-toggle {
      display: block;
    }
    
    .sub-menu {
      position: static;
      box-shadow: none;
      border: none;
      padding-left: $spacer;
    }
  }
  
  // Hide menu toggle on desktop
  .menu-toggle {
    display: none;
  }
}

Layouts Folder

The layouts folder contains SCSS files defining the main layout components of the site.

sass/layouts/
 ├── _header.scss          /* Header styles */
 ├── _footer.scss          /* Footer styles */
 ├── _sidebar.scss         /* Sidebar styles */
 ├── _grid.scss            /* Custom grid system */
 └── _posts.scss           /* Post layout styles */
Example _grid.scss
// Custom grid system for WordPress theme
.container {
  width: 100%;
  max-width: $container-max-width;
  margin-right: auto;
  margin-left: auto;
  padding-right: $grid-gutter-width / 2;
  padding-left: $grid-gutter-width / 2;
  
  // Responsive container sizes
  @each $breakpoint, $width in $breakpoints {
    @if $width > 0 {
      @include breakpoint($breakpoint) {
        @if $width < $container-max-width {
          max-width: $width - $grid-gutter-width;
        }
      }
    }
  }
}

.row {
  display: flex;
  flex-wrap: wrap;
  margin-right: -$grid-gutter-width / 2;
  margin-left: -$grid-gutter-width / 2;
}

// Column base class
[class^="col-"] {
  position: relative;
  width: 100%;
  padding-right: $grid-gutter-width / 2;
  padding-left: $grid-gutter-width / 2;
}

// Function to calculate column width
@function col-width($size, $columns: 12) {
  @return percentage($size / $columns);
}

// Generate column classes for each breakpoint
@each $breakpoint, $width in $breakpoints {
  $infix: if($width > 0, "-#{$breakpoint}", "");
  
  @include breakpoint($width) {
    @for $i from 1 through 12 {
      .col#{$infix}-#{$i} {
        flex: 0 0 col-width($i);
        max-width: col-width($i);
      }
    }
    
    // Offset classes
    @for $i from 0 through 11 {
      .offset#{$infix}-#{$i} {
        @if $i > 0 {
          margin-left: col-width($i);
        } @else {
          margin-left: 0;
        }
      }
    }
  }
}
Example _header.scss
// Site header styles
.site-header {
  background-color: $color-light;
  padding: $spacer 0;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  
  // Fixed header option
  &.fixed-header {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    z-index: map-get($z-indices, fixed);
    
    // Add padding for WordPress admin bar
    @include admin-bar-padding();
  }
  
  .container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
  }
  
  // Site branding
  .site-branding {
    display: flex;
    align-items: center;
    margin-right: $spacer;
  }
  
  .site-title {
    font-size: 1.5rem;
    font-weight: 700;
    margin: 0;
    
    a {
      color: $color-dark;
      text-decoration: none;
      
      &:hover {
        color: $color-primary;
      }
    }
  }
  
  .site-description {
    margin: 0;
    font-size: 0.875rem;
    color: $color-gray;
  }
  
  // Custom logo
  .custom-logo-link {
    margin-right: $spacer;
    
    img {
      max-height: 50px;
      width: auto;
    }
  }
  
  // Responsive styles
  @media (max-width: map-get($breakpoints, md)) {
    .container {
      flex-direction: column;
      align-items: flex-start;
    }
    
    .site-branding {
      margin-bottom: $spacer;
    }
    
    .main-navigation {
      width: 100%;
    }
  }
}

Pages Folder

The pages folder contains styles specific to individual pages.

sass/pages/
 ├── _home.scss            /* Homepage styles */
 ├── _blog.scss            /* Blog archive styles */
 ├── _single.scss          /* Single post styles */
 └── _404.scss             /* 404 page styles */
Example _home.scss
// Homepage-specific styles
.home {
  // Hero section
  .hero-section {
    background-color: $color-primary;
    color: $color-light;
    padding: $spacer * 3 0;
    margin-bottom: $spacer * 3;
    
    h1 {
      font-size: 2.5rem;
      color: $color-light;
      margin-bottom: $spacer;
      
      @include breakpoint(md) {
        font-size: 3.5rem;
      }
    }
    
    p {
      font-size: 1.25rem;
      margin-bottom: $spacer * 2;
      max-width: 800px;
    }
    
    .btn {
      margin-right: $spacer;
      margin-bottom: $spacer;
    }
  }
  
  // Featured posts section
  .featured-posts {
    margin-bottom: $spacer * 3;
    
    .section-title {
      text-align: center;
      margin-bottom: $spacer * 2;
    }
    
    .post {
      margin-bottom: $spacer * 2;
      
      .entry-title {
        font-size: 1.5rem;
      }
    }
  }
  
  // Call to action section
  .cta-section {
    background-color: $color-light;
    padding: $spacer * 3 0;
    text-align: center;
    border-top: 1px solid rgba(0, 0, 0, 0.1);
    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
    margin-bottom: $spacer * 3;
    
    h2 {
      font-size: 2rem;
      margin-bottom: $spacer;
    }
    
    p {
      max-width: 700px;
      margin: 0 auto $spacer * 2;
    }
  }
}

Main SCSS File

The main.scss file imports all other SCSS files in the correct order.

/*!
Theme Name: My WordPress Theme
Theme URI: https://example.com/my-theme
Author: Your Name
Author URI: https://example.com/
Description: A custom WordPress theme
Version: 1.0.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: my-theme
*/

// Abstracts - no CSS output
@import "abstracts/variables";
@import "abstracts/functions";
@import "abstracts/mixins";
@import "abstracts/placeholders";

// Base
@import "base/reset";
@import "base/typography";
@import "base/forms";
@import "base/accessibility";

// Layouts
@import "layouts/grid";
@import "layouts/header";
@import "layouts/footer";
@import "layouts/sidebar";
@import "layouts/posts";

// Components
@import "components/buttons";
@import "components/card";
@import "components/navigation";
@import "components/pagination";
@import "components/comments";
@import "components/widgets";

// Pages
@import "pages/home";
@import "pages/blog";
@import "pages/single";
@import "pages/404";

Enqueueing Compiled CSS in WordPress

After compiling your SCSS to CSS, you need to properly enqueue the stylesheets in your WordPress theme.

How to Enqueue CSS in functions.php

get('Version');
    
    // Enqueue main stylesheet (compiled from SASS)
    wp_enqueue_style(
        'mytheme-styles',
        get_template_directory_uri() . '/assets/css/main.min.css',
        array(),
        $theme_version
    );
    
    // Add conditional stylesheets if needed
    if (is_page_template('templates/landing-page.php')) {
        wp_enqueue_style(
            'mytheme-landing',
            get_template_directory_uri() . '/assets/css/landing.min.css',
            array('mytheme-styles'),
            $theme_version
        );
    }
    
    // WooCommerce styles (only if plugin is active)
    if (class_exists('WooCommerce')) {
        wp_enqueue_style(
            'mytheme-woocommerce',
            get_template_directory_uri() . '/assets/css/woocommerce.min.css',
            array('mytheme-styles'),
            $theme_version
        );
    }
}
add_action('wp_enqueue_scripts', 'mytheme_enqueue_styles');

/**
 * Enqueue block editor assets
 */
function mytheme_editor_assets() {
    // Get theme version
    $theme_version = wp_get_theme()->get('Version');
    
    // Editor styles
    wp_enqueue_style(
        'mytheme-editor-styles',
        get_template_directory_uri() . '/assets/css/editor.min.css',
        array(),
        $theme_version
    );
}
add_action('enqueue_block_editor_assets', 'mytheme_editor_assets');

Gulp Task for Separate Editor CSS

// Create editor styles from SASS
function editorStyles() {
  return gulp.src('./sass/editor.scss')
    .pipe(sourcemaps.init())
    .pipe(sass().on('error', sass.logError))
    .pipe(postcss([
      autoprefixer(),
      cssnano()
    ]))
    .pipe(rename({
      suffix: '.min'
    }))
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest('./assets/css'));
}

// Add to your exports
exports.editorStyles = editorStyles;
exports.default = gulp.series(styles, editorStyles, watch);

Supporting WordPress Block Editor with SASS

For Gutenberg Block Editor support, create a separate SCSS file for editor styles:

// editor.scss

// Import shared variables and mixins
@import "abstracts/variables";
@import "abstracts/functions";
@import "abstracts/mixins";

// Import typography and base styles that should be available in the editor
@import "base/typography";

// Editor-specific styles
.wp-block {
  max-width: $content-width;
  
  &[data-align="wide"] {
    max-width: $content-width * 1.2;
  }
  
  &[data-align="full"] {
    max-width: none;
  }
}

// Style the editor to match your theme
.editor-styles-wrapper {
  font-family: $font-family-base;
  color: $body-color;
  
  h1, h2, h3, h4, h5, h6 {
    font-family: $font-family-heading;
    color: $color-dark;
  }
  
  // Style specific blocks to match front-end
  .wp-block-quote {
    border-left: 4px solid $color-primary;
    padding-left: $spacer;
  }
  
  .wp-block-button {
    .wp-block-button__link {
      background-color: $color-primary;
      color: $color-light;
      
      &:hover {
        background-color: darken($color-primary, 10%);
      }
    }
    
    &.is-style-outline {
      .wp-block-button__link {
        background-color: transparent;
        border: 1px solid $color-primary;
        color: $color-primary;
        
        &:hover {
          background-color: $color-primary;
          color: $color-light;
        }
      }
    }
  }
}

SASS Performance and Optimization

As your SASS codebase grows, it's important to consider performance and optimization best practices.

SASS Best Practices

Avoid Deep Nesting

Avoid This
// Excessive nesting
.header {
  .navigation {
    .nav-list {
      .nav-item {
        .nav-link {
          // 5 levels deep!
          &:hover {
            color: red;
          }
        }
      }
    }
  }
}
Use This Instead
// Flatter selectors with BEM
.nav-list {
  // Styles...
}

.nav-item {
  // Styles...
}

.nav-link {
  // Styles...
  
  &:hover {
    color: red;
  }
}

Use Variables for Repeated Values

Avoid This
// Hardcoded values
.header {
  background-color: #3a86ff;
}

.button {
  background-color: #3a86ff;
}

.footer {
  border-top: 1px solid #3a86ff;
}
Use This Instead
// Variables for consistency
$color-primary: #3a86ff;

.header {
  background-color: $color-primary;
}

.button {
  background-color: $color-primary;
}

.footer {
  border-top: 1px solid $color-primary;
}

Modularize Your Code

Split your SASS into logical modules using partials. This makes your codebase more maintainable and easier to navigate.

Optimize Compiled CSS

Use compression and autoprefixing in your build process to minimize the final CSS file size and ensure cross-browser compatibility.

// Optimization setup in gulpfile.js
function styles() {
  return gulp.src('./sass/main.scss')
    .pipe(sourcemaps.init())
    .pipe(sass().on('error', sass.logError))
    .pipe(postcss([
      autoprefixer(),
      cssnano({
        preset: ['default', {
          discardComments: {
            removeAll: true
          },
          normalizeWhitespace: true
        }]
      })
    ]))
    .pipe(rename({
      suffix: '.min'
    }))
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest('./assets/css'));
}

Use Source Maps for Debugging

Source maps help you debug your SASS code by mapping the compiled CSS back to the original SCSS files.

Take Advantage of SASS Features

Leverage SASS features like functions, mixins, and extends to create reusable code patterns.

Advanced Optimization Techniques

Critical CSS

Extract critical CSS for above-the-fold content to improve initial page load performance.

// Install critical CSS package
// npm install --save-dev critical

const critical = require('critical');

// Generate critical CSS
function criticalCSS() {
  return critical.generate({
    base: './',
    src: 'index.html',
    target: {
      css: 'assets/css/critical.min.css',
      html: 'index-critical.html',
      inline: true
    },
    width: 1300,
    height: 900,
    minify: true
  });
}

CSS Code Splitting

Split your CSS into multiple files based on usage to avoid loading unnecessary styles.

// Create separate CSS bundles for different template types
function templateStyles() {
  // Array of template-specific styles
  const templates = [
    'home',
    'blog',
    'shop',
    'contact'
  ];
  
  // Create a stream for each template
  const streams = templates.map(template => {
    return gulp.src(`./sass/templates/${template}.scss`)
      .pipe(sass().on('error', sass.logError))
      .pipe(postcss([autoprefixer(), cssnano()]))
      .pipe(rename({ suffix: '.min' }))
      .pipe(gulp.dest('./assets/css/templates'));
  });
  
  // Merge all streams
  return merge(streams);
}

PurgeCSS for WordPress

Remove unused CSS from your final stylesheet to reduce file size.

// Install PurgeCSS
// npm install --save-dev gulp-purgecss

const purgecss = require('gulp-purgecss');

// PurgeCSS for production build
function purgeCSS() {
  return gulp.src('./assets/css/main.min.css')
    .pipe(purgecss({
      content: [
        './**/*.php',
        './assets/js/**/*.js'
      ],
      safelist: {
        standard: [/^wp-/, /^has-/, /^is-/, /^align/, /^admin-/],
        deep: [/^(has|is|wp)-.*$/],
        greedy: [/^(wp-block-|woocommerce-|widget_)/]
      }
    }))
    .pipe(rename({
      suffix: '.purged'
    }))
    .pipe(gulp.dest('./assets/css'));
}

Additional Resources for SASS Development

Practical Exercises

Let's apply what we've learned with some practical exercises for SASS implementation in WordPress.

Exercise 1: Convert CSS to SCSS

Take the following CSS code and convert it to well-organized SCSS using nesting, variables, and mixins.

Original CSS

/* Navigation styles */
.main-menu {
  background-color: #333;
  padding: 15px 0;
}

.main-menu ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
}

.main-menu li {
  margin: 0 10px;
}

.main-menu a {
  color: white;
  text-decoration: none;
  font-weight: bold;
  padding: 5px 10px;
}

.main-menu a:hover {
  background-color: #555;
  border-radius: 3px;
}

/* Button styles */
.button {
  display: inline-block;
  padding: 10px 20px;
  background-color: #2c7ad6;
  color: white;
  text-decoration: none;
  border-radius: 4px;
  font-weight: bold;
}

.button:hover {
  background-color: #1c5fa8;
}

.button.secondary {
  background-color: #6c757d;
}

.button.secondary:hover {
  background-color: #5a6268;
}

.button.large {
  padding: 15px 30px;
  font-size: 18px;
}

.button.small {
  padding: 5px 10px;
  font-size: 14px;
}

/* Media queries */
@media (max-width: 768px) {
  .main-menu ul {
    flex-direction: column;
  }
  
  .main-menu li {
    margin: 5px 0;
  }
}

Converted SCSS Solution

// Variables
$color-dark: #333;
$color-dark-hover: #555;
$color-primary: #2c7ad6;
$color-primary-hover: #1c5fa8;
$color-secondary: #6c757d;
$color-secondary-hover: #5a6268;
$color-white: white;

$border-radius-small: 3px;
$border-radius-medium: 4px;

$font-size-small: 14px;
$font-size-base: 16px;
$font-size-large: 18px;

// Mixins
@mixin button-variant($bg-color, $hover-color) {
  background-color: $bg-color;
  color: $color-white;
  
  &:hover {
    background-color: $hover-color;
  }
}

@mixin button-size($padding-x, $padding-y, $font-size) {
  padding: $padding-y $padding-x;
  font-size: $font-size;
}

// Breakpoint mixin
@mixin breakpoint($point) {
  @if $point == medium {
    @media (max-width: 768px) { @content; }
  }
}

// Navigation styles
.main-menu {
  background-color: $color-dark;
  padding: 15px 0;
  
  ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    
    @include breakpoint(medium) {
      flex-direction: column;
    }
  }
  
  li {
    margin: 0 10px;
    
    @include breakpoint(medium) {
      margin: 5px 0;
    }
  }
  
  a {
    color: $color-white;
    text-decoration: none;
    font-weight: bold;
    padding: 5px 10px;
    
    &:hover {
      background-color: $color-dark-hover;
      border-radius: $border-radius-small;
    }
  }
}

// Button styles
.button {
  display: inline-block;
  text-decoration: none;
  border-radius: $border-radius-medium;
  font-weight: bold;
  @include button-variant($color-primary, $color-primary-hover);
  @include button-size(20px, 10px, $font-size-base);
  
  &.secondary {
    @include button-variant($color-secondary, $color-secondary-hover);
  }
  
  &.large {
    @include button-size(30px, 15px, $font-size-large);
  }
  
  &.small {
    @include button-size(10px, 5px, $font-size-small);
  }
}

Exercise 2: Create SCSS for WordPress Gutenberg Blocks

Create a SCSS implementation for styling a custom WordPress block with variations.

Solution: Custom Feature Block SCSS

// _block-feature.scss

// Block variables
$feature-block-bg: $color-light;
$feature-block-padding: $spacer * 2;
$feature-block-border-radius: 8px;
$feature-block-margin: $spacer * 3;

// Feature block component
.wp-block-mytheme-feature {
  background-color: $feature-block-bg;
  padding: $feature-block-padding;
  border-radius: $feature-block-border-radius;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
  margin-bottom: $feature-block-margin;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
  
  // Inner block layout
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  
  // Block icon
  &__icon {
    font-size: 3rem;
    margin-bottom: $spacer;
    color: $color-primary;
    
    svg {
      width: 64px;
      height: 64px;
    }
  }
  
  // Block title
  &__title {
    font-size: 1.5rem;
    margin-bottom: $spacer;
    color: $color-dark;
  }
  
  // Block content
  &__content {
    color: $color-gray;
    margin-bottom: $spacer;
    
    p:last-child {
      margin-bottom: 0;
    }
  }
  
  // Hover effect
  &:hover {
    transform: translateY(-5px);
    box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15);
  }
  
  // Block variations/styles
  &.is-style-primary {
    background-color: $color-primary;
    color: $color-white;
    
    .wp-block-mytheme-feature__title {
      color: $color-white;
    }
    
    .wp-block-mytheme-feature__content {
      color: rgba(255, 255, 255, 0.8);
    }
    
    .wp-block-mytheme-feature__icon {
      color: $color-white;
    }
  }
  
  &.is-style-outlined {
    background-color: transparent;
    border: 2px solid $color-primary;
    box-shadow: none;
    
    .wp-block-mytheme-feature__icon {
      color: $color-primary;
    }
  }
  
  &.is-style-minimal {
    background-color: transparent;
    box-shadow: none;
    padding: 0;
    
    &:hover {
      transform: none;
    }
  }
  
  // Responsive styles
  @include breakpoint(md) {
    padding: $feature-block-padding * 0.75;
    
    &__icon svg {
      width: 48px;
      height: 48px;
    }
    
    &__title {
      font-size: 1.25rem;
    }
  }
  
  @include breakpoint(sm) {
    padding: $feature-block-padding * 0.5;
    
    &__icon svg {
      width: 40px;
      height: 40px;
    }
    
    &__title {
      font-size: 1.1rem;
    }
  }
}

// Editor-specific styles
.editor-styles-wrapper {
  .wp-block-mytheme-feature {
    // Add any editor-specific styles
  }
}

Registering Block Styles in WordPress

 'primary',
            'label'        => __('Primary', 'mytheme'),
            'style_handle' => 'mytheme-styles',
        )
    );
    
    register_block_style(
        'mytheme/feature',
        array(
            'name'         => 'outlined',
            'label'        => __('Outlined', 'mytheme'),
            'style_handle' => 'mytheme-styles',
        )
    );
    
    register_block_style(
        'mytheme/feature',
        array(
            'name'         => 'minimal',
            'label'        => __('Minimal', 'mytheme'),
            'style_handle' => 'mytheme-styles',
        )
    );
}
add_action('init', 'mytheme_register_block_styles');

Exercise 3: WordPress Theme Color Scheme using SASS

Create a SASS implementation that allows easy theme color scheme customization.

Solution: Color Scheme SCSS Architecture

// _color-schemes.scss

// Base color schemes
$color-schemes: (
  'default': (
    'primary': #3a86ff,
    'secondary': #ff006e,
    'accent': #ffbe0b,
    'text': #333333,
    'background': #ffffff,
    'border': #e0e0e0
  ),
  'dark': (
    'primary': #5e96ff,
    'secondary': #ff4b93,
    'accent': #ffcf4b,
    'text': #f1f1f1,
    'background': #1a1a1a,
    'border': #444444
  ),
  'ocean': (
    'primary': #0077b6,
    'secondary': #00b4d8,
    'accent': #90e0ef,
    'text': #212529,
    'background': #f8f9fa,
    'border': #caf0f8
  ),
  'forest': (
    'primary': #2d6a4f,
    'secondary': #40916c,
    'accent': #b7e4c7,
    'text': #212529,
    'background': #f8f9fa,
    'border': #d8f3dc
  )
);

// Get current color scheme from WordPress customizer
$current-scheme: get-theme-mod('color_scheme', 'default');

// Function to get color from the current scheme
@function theme-color($color-name) {
  @if map-has-key(map-get($color-schemes, $current-scheme), $color-name) {
    @return map-get(map-get($color-schemes, $current-scheme), $color-name);
  } @else {
    @error "Color '#{$color-name}' not found in color scheme '#{$current-scheme}'";
    @return null;
  }
}

// Set theme colors based on selected scheme
$color-primary: theme-color('primary');
$color-secondary: theme-color('secondary');
$color-accent: theme-color('accent');
$body-color: theme-color('text');
$body-bg: theme-color('background');
$border-color: theme-color('border');

// Generate CSS custom properties for the color scheme
:root {
  @each $color-name, $color-value in map-get($color-schemes, $current-scheme) {
    --theme-#{$color-name}: #{$color-value};
  }
}

// CSS for color scheme body classes
@each $scheme-name, $scheme-colors in $color-schemes {
  body.color-scheme-#{$scheme-name} {
    @each $color-name, $color-value in $scheme-colors {
      --theme-#{$color-name}: #{$color-value};
    }
    
    background-color: var(--theme-background);
    color: var(--theme-text);
  }
}

WordPress Integration for Color Schemes

add_section('mytheme_color_scheme', array(
        'title'    => __('Color Scheme', 'mytheme'),
        'priority' => 30,
    ));
    
    // Add color scheme setting
    $wp_customize->add_setting('color_scheme', array(
        'default'           => 'default',
        'sanitize_callback' => 'sanitize_key',
        'transport'         => 'refresh',
    ));
    
    // Add color scheme control
    $wp_customize->add_control('color_scheme', array(
        'label'    => __('Select Color Scheme', 'mytheme'),
        'section'  => 'mytheme_color_scheme',
        'type'     => 'select',
        'choices'  => array(
            'default' => __('Default', 'mytheme'),
            'dark'    => __('Dark', 'mytheme'),
            'ocean'   => __('Ocean', 'mytheme'),
            'forest'  => __('Forest', 'mytheme'),
        ),
    ));
}
add_action('customize_register', 'mytheme_customizer_color_schemes');

/**
 * Add color scheme body class
 */
function mytheme_color_scheme_body_class($classes) {
    $color_scheme = get_theme_mod('color_scheme', 'default');
    $classes[] = 'color-scheme-' . $color_scheme;
    return $classes;
}
add_filter('body_class', 'mytheme_color_scheme_body_class');

Conclusion: The Power of SASS in WordPress Development

SASS/SCSS brings powerful tools to your CSS workflow, making it more organized, maintainable, and efficient. By adopting SASS in your WordPress development process, you can:

  • Improve Code Organization: Using partials, nesting, and modular architecture
  • Enhance Maintainability: With variables, mixins, and functions
  • Increase Development Speed: Through reusable components and patterns
  • Build Responsive Themes: Using mixins for breakpoints and responsive designs
  • Future-Proof Your Code: With a structured, scalable approach to styling

The time invested in learning and implementing SASS pays off in the long run, especially for WordPress theme development where maintaining consistent styles across complex layouts and multiple templates is crucial.

As you continue your WordPress development journey, keep exploring advanced SASS techniques and integrating them with modern WordPress features like the Block Editor. This combination of powerful preprocessing capabilities and WordPress flexibility will enable you to create themes that are both visually impressive and maintainable.