SASS Theme Development Guide

SASS Theme Development Guide

This guide covers how to develop FearlessCMS themes that use SASS (Syntactically Awesome Style Sheets) for CSS preprocessing. This is useful for complex themes that benefit from SASS features like variables, mixins, and nested rules.

When to Use SASS

Consider using SASS for your theme if you need:

SASS Setup

1. Install SASS

You'll need to install SASS on your development machine:

# Using npm (recommended)
npm install -g sass

# Using Ruby (if you have Ruby installed)
gem install sass

# Using Homebrew (macOS)
brew install sass/sass/sass

2. Theme Structure with SASS

Organize your SASS files in a logical structure:

themes/your-sass-theme/
├── templates/
│   ├── home.html
│   ├── page.html
│   ├── blog.html
│   └── 404.html
├── assets/
│   ├── sass/
│   │   ├── main.scss          # Main SASS file
│   │   ├── _variables.scss    # Variables
│   │   ├── _mixins.scss       # Mixins
│   │   ├── _base.scss         # Base styles
│   │   ├── _layout.scss       # Layout styles
│   │   ├── _components.scss   # Component styles
│   │   └── _utilities.scss    # Utility classes
│   ├── style.css              # Compiled CSS (generated)
│   ├── images/
│   └── js/
├── theme.json
├── config.json
└── README.md

3. SASS File Organization

main.scss (Main Entry Point)

// Import all SASS files
@import 'variables';
@import 'mixins';
@import 'base';
@import 'layout';
@import 'components';
@import 'utilities';

_variables.scss (Variables)

// Colors
$primary-color: #007bff;
$secondary-color: #6c757d;
$success-color: #28a745;
$danger-color: #dc3545;
$warning-color: #ffc107;
$info-color: #17a2b8;

// Typography
$font-family-base: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
$font-size-base: 1rem;
$line-height-base: 1.6;

// Spacing
$spacing-unit: 1rem;
$container-max-width: 1200px;

// Breakpoints
$breakpoint-sm: 576px;
$breakpoint-md: 768px;
$breakpoint-lg: 992px;
$breakpoint-xl: 1200px;

// Theme options integration
$theme-colors: (
  'blue': #007bff,
  'green': #28a745,
  'purple': #6f42c1,
  'orange': #fd7e14
);

_mixins.scss (Reusable Mixins)

// Responsive breakpoint mixin
@mixin respond-to($breakpoint) {
  @if $breakpoint == sm {
    @media (min-width: $breakpoint-sm) { @content; }
  } @else if $breakpoint == md {
    @media (min-width: $breakpoint-md) { @content; }
  } @else if $breakpoint == lg {
    @media (min-width: $breakpoint-lg) { @content; }
  } @else if $breakpoint == xl {
    @media (min-width: $breakpoint-xl) { @content; }
  }
}

// Button mixin
@mixin button($bg-color: $primary-color, $text-color: white) {
  background-color: $bg-color;
  color: $text-color;
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.2s ease;

  &:hover {
    background-color: darken($bg-color, 10%);
  }
}

// Card mixin
@mixin card($bg-color: white, $border-color: #e9ecef) {
  background-color: $bg-color;
  border: 1px solid $border-color;
  border-radius: 8px;
  padding: $spacing-unit;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

_base.scss (Base Styles)

// Reset and base styles
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html {
  font-size: 16px;
}

body {
  font-family: $font-family-base;
  font-size: $font-size-base;
  line-height: $line-height-base;
  color: $text-color;
  background-color: $bg-color;
}

// Typography
h1, h2, h3, h4, h5, h6 {
  margin-bottom: $spacing-unit;
  font-weight: 600;
  line-height: 1.2;
}

h1 { font-size: 2.5rem; }
h2 { font-size: 2rem; }
h3 { font-size: 1.75rem; }
h4 { font-size: 1.5rem; }
h5 { font-size: 1.25rem; }
h6 { font-size: 1rem; }

p {
  margin-bottom: $spacing-unit;
}

a {
  color: $primary-color;
  text-decoration: none;

  &:hover {
    text-decoration: underline;
  }
}

_layout.scss (Layout Styles)

// Container
.container {
  max-width: $container-max-width;
  margin: 0 auto;
  padding: 0 $spacing-unit;

  @include respond-to(md) {
    padding: 0 ($spacing-unit * 2);
  }
}

// Grid system
.grid {
  display: grid;
  gap: $spacing-unit;

  &--2-cols {
    grid-template-columns: 1fr;

    @include respond-to(md) {
      grid-template-columns: 1fr 1fr;
    }
  }

  &--3-cols {
    grid-template-columns: 1fr;

    @include respond-to(md) {
      grid-template-columns: repeat(3, 1fr);
    }
  }
}

// Header
.header {
  background-color: $header-bg;
  padding: $spacing-unit 0;
  border-bottom: 1px solid $border-color;
}

// Main content
.main {
  padding: ($spacing-unit * 2) 0;
  min-height: 60vh;
}

// Footer
.footer {
  background-color: $footer-bg;
  color: $footer-text-color;
  padding: ($spacing-unit * 2) 0;
  margin-top: auto;
}

_components.scss (Component Styles)

// Buttons
.btn {
  @include button;

  &--secondary {
    @include button($secondary-color);
  }

  &--success {
    @include button($success-color);
  }

  &--danger {
    @include button($danger-color);
  }
}

// Cards
.card {
  @include card;

  &--featured {
    @include card($primary-color, $primary-color);
    color: white;
  }
}

// Navigation
.nav {
  display: flex;
  align-items: center;

  &__list {
    display: flex;
    list-style: none;
    gap: $spacing-unit;
  }

  &__link {
    color: $nav-link-color;
    text-decoration: none;
    padding: 0.5rem;

    &:hover {
      color: $nav-link-hover-color;
    }
  }
}

// Blog posts
.blog-post {
  margin-bottom: ($spacing-unit * 2);
  padding-bottom: ($spacing-unit * 2);
  border-bottom: 1px solid $border-color;

  &:last-child {
    border-bottom: none;
  }

  &__title {
    margin-bottom: $spacing-unit;

    a {
      color: $text-color;
      text-decoration: none;

      &:hover {
        color: $primary-color;
      }
    }
  }

  &__meta {
    color: $text-muted;
    font-size: 0.9rem;
    margin-bottom: $spacing-unit;
  }

  &__excerpt {
    color: $text-muted;
    margin-bottom: $spacing-unit;
  }
}

Development Workflow with SASS

1. Watch Mode

Use SASS watch mode during development:

# Watch for changes and compile automatically
sass --watch assets/sass/main.scss:assets/style.css

# Or with compressed output
sass --watch assets/sass/main.scss:assets/style.css --style compressed

2. Build Process

For production builds:

# Compile once with compressed output
sass assets/sass/main.scss:assets/style.css --style compressed

# Or create a build script in package.json

3. Package.json Scripts

Create a package.json file in your theme directory:

{
  "name": "your-sass-theme",
  "version": "1.0.0",
  "scripts": {
    "sass:watch": "sass --watch assets/sass/main.scss:assets/style.css",
    "sass:build": "sass assets/sass/main.scss:assets/style.css --style compressed",
    "sass:dev": "sass assets/sass/main.scss:assets/style.css --style expanded"
  },
  "devDependencies": {
    "sass": "^1.32.0"
  }
}

Then use:

npm run sass:watch  # Development
npm run sass:build  # Production
npm run sass:dev    # Development with expanded output

Theme Options Integration

CSS Custom Properties with SASS

Use SASS to generate CSS custom properties for theme options:

// _variables.scss
$theme-colors: (
  'blue': #007bff,
  'green': #28a745,
  'purple': #6f42c1,
  'orange': #fd7e14
);

// Generate CSS custom properties
:root {
  @each $name, $color in $theme-colors {
    --color-#{$name}: #{$color};
  }

  --primary-color: var(--color-blue);
  --secondary-color: var(--color-gray);
}

// Theme-specific classes
@each $name, $color in $theme-colors {
  .theme-#{$name} {
    --primary-color: var(--color-#{$name});
  }
}

Dynamic Theme Options

Create SASS functions to handle theme options:

// _functions.scss
@function theme-color($color-name) {
  @return var(--color-#{$color-name});
}

@function theme-option($option-name) {
  @return var(--theme-#{$option-name});
}

// Usage
.button {
  background-color: theme-color('primary');
  color: white;
}

.sidebar {
  @if theme-option('show-sidebar') {
    display: block;
  } @else {
    display: none;
  }
}

Example: Complete SASS Theme

Theme Structure

themes/sass-example/
├── templates/
│   ├── home.html
│   ├── page.html
│   ├── blog.html
│   └── 404.html
├── assets/
│   ├── sass/
│   │   ├── main.scss
│   │   ├── _variables.scss
│   │   ├── _mixins.scss
│   │   ├── _base.scss
│   │   ├── _layout.scss
│   │   ├── _components.scss
│   │   └── _utilities.scss
│   ├── style.css
│   └── images/
├── theme.json
├── config.json
├── package.json
└── README.md

main.scss

// Import all SASS files
@import 'variables';
@import 'mixins';
@import 'base';
@import 'layout';
@import 'components';
@import 'utilities';

// Theme-specific overrides
@import 'theme-overrides';

Template Usage

<!DOCTYPE html>
<html lang="en" class="theme-{{themeOptions.colorScheme}}">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{title}} - {{siteName}}</title>
    <link rel="stylesheet" href="/themes/{{theme}}/assets/style.css">
</head>
<body>
    <header class="header">
        <div class="container">
            {{#if themeOptions.logo}}
                <img src="/{{themeOptions.logo}}" alt="{{siteName}}" class="logo">
            {{else}}
                <h1>{{siteName}}</h1>
            {{/if}}

            <nav class="nav">
                {{#if menu.main}}
                    <ul class="nav__list">
                        {{#each menu.main}}
                            <li><a href="/{{url}}" class="nav__link">{{title}}</a></li>
                        {{/each}}
                    </ul>
                {{/if}}
            </nav>
        </div>
    </header>

    <main class="main">
        <div class="container">
            <article class="content">
                {{content}}
            </article>
        </div>
    </main>

    <footer class="footer">
        <div class="container">
            <p>&copy; 2025 {{siteName}}</p>
        </div>
    </footer>
</body>
</html>

Best Practices

1. File Organization

2. Variable Management

3. Mixin Usage

4. Performance

5. Maintenance

Troubleshooting

Common Issues

  1. SASS not compiling: Check file paths and syntax
  2. Variables not working: Ensure proper import order
  3. Large CSS output: Use @extend instead of mixins where appropriate
  4. Slow compilation: Reduce file complexity and nesting

Debug Tips

Deployment

1. Build for Production

# Compile with compressed output
sass assets/sass/main.scss:assets/style.css --style compressed

# Or use npm script
npm run sass:build

2. Include in Theme Package

Make sure to include the compiled style.css file in your theme package, not the SASS source files.

3. Documentation

Include SASS setup instructions in your theme's README.md for developers who want to modify the theme.

This approach gives you the power of SASS while maintaining compatibility with FearlessCMS's simple theme system.