1. SCSS Syntax and Structure Fundamentals

1.1 SCSS vs Sass Syntax Differences and Usage

Feature SCSS Syntax Sass (Indented) Syntax Notes
File Extension .scss .sass SCSS is CSS-compatible superset
Braces & Semicolons Required { } ; Not used (indentation-based) SCSS more familiar to CSS developers
Nesting Curly braces { } Indentation (2 spaces) Both support same nesting features
Mixins @mixin name { } =name Sass uses = and + shorthand
Include @include name; +name Both compile to same CSS
Comments // or /* */ // or /* */ Same comment syntax

Example: SCSS vs Sass comparison

// SCSS Syntax (.scss)
$primary-color: #333;

.nav {
  background: $primary-color;
  ul {
    margin: 0;
    li {
      display: inline-block;
    }
  }
}

// Sass Syntax (.sass)
$primary-color: #333

.nav
  background: $primary-color
  ul
    margin: 0
    li
      display: inline-block
Note: SCSS is recommended for most projects due to CSS compatibility. All valid CSS is valid SCSS.

1.2 Nesting Rules and Best Practices

Nesting Type Syntax Best Practice Use Case
Basic Nesting parent { child { } } Limit to 3-4 levels deep Component structure organization
Selector Nesting .parent { .child { } } Mirror HTML structure Maintain readability and scope
Pseudo-classes &:hover, &:focus Keep with parent selector State variations of elements
Media Queries @media { } inside selector Nest within component Component-level responsive design
Property Nesting font: { size: 12px; } Use sparingly Related property groups
Deep Nesting Warning > 4 levels Refactor or use BEM Avoid specificity issues

Example: Proper nesting with depth limit

// Good: 3 levels, clear structure
.card {
  padding: 1rem;
  
  &__header {
    font-weight: bold;
    
    &:hover {
      color: blue;
    }
  }
  
  @media (min-width: 768px) {
    padding: 2rem;
  }
}

// Bad: Too deep, overly specific
.nav {
  ul {
    li {
      a {
        span {  // 5 levels - avoid!
          color: red;
        }
      }
    }
  }
}
Warning: Deep nesting increases CSS specificity and file size. Keep selectors 3 levels or less when possible.

1.3 Parent Selector Reference (&) and Pseudo-selectors

Usage Syntax Output CSS Common Use Case
Pseudo-class &:hover .btn:hover State changes (hover, focus, active)
Pseudo-element &::before .box::before Generated content
Modifier Class &--large .btn--large BEM modifier pattern
Element Class &__icon .btn__icon BEM element pattern
Compound Selector &.active .tab.active State class combination
Parent Reference .theme-dark & .theme-dark .btn Context-based styling
Attribute Selector &[disabled] .btn[disabled] Attribute-based styling
Multiple Parents &-prefix-&-suffix Complex string building Dynamic class generation

Example: Parent selector (&) patterns

// Pseudo-selectors
.button {
  background: blue;
  
  &:hover { background: darkblue; }
  &:focus { outline: 2px solid blue; }
  &::after { content: '→'; }
}

// BEM Pattern
.card {
  border: 1px solid #ccc;
  
  &__title {
    font-size: 1.5rem;
  }
  
  &--featured {
    border-color: gold;
  }
}

// Context Selector
.sidebar {
  width: 200px;
  
  .mobile & {
    width: 100%;
  }
}

// Compound Classes
.nav-item {
  color: black;
  
  &.active {
    color: blue;
    font-weight: bold;
  }
}

1.4 Property Nesting and Shorthand Syntax

Property Group SCSS Nested Syntax CSS Output Use Case
font font: { size: 16px; weight: bold; } font-size: 16px; font-weight: bold; Typography properties
margin margin: { top: 10px; bottom: 10px; } margin-top: 10px; margin-bottom: 10px; Spacing control
padding padding: { left: 20px; right: 20px; } padding-left: 20px; padding-right: 20px; Inner spacing
border border: { width: 1px; style: solid; } border-width: 1px; border-style: solid; Border definitions
background background: { color: #fff; size: cover; } background-color: #fff; background-size: cover; Background layers
text text: { align: center; decoration: underline; } text-align: center; text-decoration: underline; Text formatting

Example: Property nesting examples

.box {
  font: {
    family: Arial, sans-serif;
    size: 14px;
    weight: 600;
  }
  
  margin: {
    top: 1rem;
    bottom: 1rem;
  }
  
  border: {
    top: 2px solid blue;
    bottom: 1px solid gray;
    radius: 4px;
  }
}

// Output CSS:
// .box {
//   font-family: Arial, sans-serif;
//   font-size: 14px;
//   font-weight: 600;
//   margin-top: 1rem;
//   margin-bottom: 1rem;
//   border-top: 2px solid blue;
//   border-bottom: 1px solid gray;
//   border-radius: 4px;
// }
Note: Property nesting is rarely used in practice. Standard CSS syntax is more common and readable.

1.5 Comments (// vs /* */) and Documentation

Comment Type Syntax Compiled Output Best Use
Silent Comment // comment Not included in CSS Developer notes, TODOs, explanations
Loud Comment /* comment */ Included in CSS output Copyright, section headers, docs
Multi-line Silent // Line 1
// Line 2
Not in CSS Block explanations
Multi-line Loud /* Line 1
Line 2 */
Preserved in CSS Documentation blocks
Force Comment /*! Important */ Always kept (even compressed) Licenses, copyright, attribution
Interpolation /* Version: #{$ver} */ Variable value inserted Dynamic documentation

Example: Comment types and usage

// This comment won't appear in CSS
// Used for developer notes and explanations

/* This comment will appear in CSS output */
/* Use for section headers and user-facing docs */

/*! 
 * This comment is ALWAYS preserved
 * Copyright 2025 - Company Name
 */

$version: '2.1.0';

/* Project Version: #{$version} */

// =========================
// Component: Navigation Bar
// =========================
.navbar {
  /* Navigation bar styles */
  background: #333;
  
  // TODO: Add responsive breakpoints
  // FIXME: z-index conflict with modal
}

// Compressed output will remove /* */ but keep /*! */

Silent Comments (//)

  • Development notes
  • Code explanations
  • TODOs and FIXMEs
  • Temporary debugging

Loud Comments (/* */)

  • Section dividers
  • API documentation
  • Generated content notes
  • Licenses (use /*! */)

1.6 File Extensions and Import Conventions

File Type Extension Naming Pattern Purpose
SCSS Files .scss styles.scss Main stylesheet files
Sass Files .sass styles.sass Indented syntax files
Partial Files .scss _partial.scss Not compiled directly (imported only)
CSS Output .css styles.css Compiled output for browser
Source Map .css.map styles.css.map Debug mapping to source SCSS
Import Pattern @import 'partial'; or @use 'module'; NEW

Example: File structure and import conventions

// File structure:
// styles/
//   ├── main.scss          (entry point)
//   ├── _variables.scss    (partial)
//   ├── _mixins.scss       (partial)
//   └── components/
//       ├── _button.scss   (partial)
//       └── _card.scss     (partial)

// main.scss (compiled to main.css)
@import 'variables';
@import 'mixins';
@import 'components/button';
@import 'components/card';

// Modern approach with @use
@use 'variables' as vars;
@use 'mixins' as mx;
@use 'components/button';

// Partial file naming: _variables.scss
// Underscore prevents direct compilation
// Import without underscore or extension
@import 'variables';  // finds _variables.scss
Import Method Syntax Status Notes
@import DEPRECATED @import 'file'; Legacy, being phased out Global namespace, can cause conflicts
@use NEW @use 'file'; Recommended modern approach Namespaced, prevents conflicts
@forward NEW @forward 'file'; Module re-exporting Create library entry points
Index Files @use 'components'; Loads _index.scss Folder-level imports
Note: Use underscore prefix for partials to prevent direct compilation. Modern projects should use @use instead of @import.
Warning: @import is deprecated and will be removed from Sass. Migrate to @use and @forward for future compatibility.

2. Variables and Data Types Reference

2.1 Variable Declaration with $ Syntax

Concept Syntax Example Notes
Basic Declaration $variable-name: value; $primary-color: #3498db; Use hyphen or underscore naming
Variable Usage property: $variable-name; color: $primary-color; Reference declared variable
Naming Convention $kebab-case $btn-primary-bg Recommended: lowercase with hyphens
Underscore Equivalence $var-name === $var_name $main-color = $main_color Hyphens and underscores are interchangeable
Reassignment $var: new-value; $size: 20px; Variables can be reassigned
Required Prefix Must start with $ $font-size font-size ✗ (invalid variable)

Example: Variable declaration and usage

// Color variables
$primary-color: #3498db;
$secondary-color: #2ecc71;
$text-color: #333;

// Spacing variables
$spacing-unit: 8px;
$margin-base: $spacing-unit * 2;

// Typography
$font-primary: 'Helvetica', sans-serif;
$font-size-base: 16px;

// Usage
.button {
  background: $primary-color;
  color: white;
  font-family: $font-primary;
  margin: $margin-base;
  
  &:hover {
    background: $secondary-color;
  }
}

2.2 Variable Scope (global, local, !global flag)

Scope Type Definition Location Accessibility Example
Global Scope Top-level (outside blocks) Accessible everywhere $global-var: value;
Local Scope Inside { } blocks Only within that block .class { $local: value; }
!global Flag Inside block with flag Creates/modifies global variable $var: value !global;
Shadowing Local var with same name Local overrides in scope Global $x shadowed by local $x
Function Scope Inside @function Isolated to function @function { $local: 1; }
Mixin Scope Inside @mixin Isolated to mixin @mixin { $local: 1; }

Example: Variable scope demonstration

// Global variable
$color: red;

.component {
  // Local variable (only in this block)
  $local-color: blue;
  color: $local-color;      // blue
  background: $color;       // red (global)
}

.another {
  color: $color;            // red (global accessible)
  // color: $local-color;   // ERROR: undefined
}

// Modifying global from local scope
.modifier {
  $color: green !global;    // Changes global $color
}

.test {
  color: $color;            // green (global was modified)
}

// Shadowing example
$size: 10px;

.shadow {
  $size: 20px;              // Local, shadows global
  font-size: $size;         // 20px (local)
  
  .nested {
    font-size: $size;       // 20px (parent local)
  }
}

.no-shadow {
  font-size: $size;         // 10px (global)
}
Warning: Use !global sparingly. It can lead to unexpected side effects and makes code harder to maintain.

2.3 Variable Interpolation #{} Syntax

Use Case Syntax Example Output
Selector Interpolation .#{$var} { } $name: 'header';
.#{$name} { }
.header { }
Property Interpolation #{$var}: value; #{$prop}: 10px; margin: 10px;
String Interpolation "text #{$var}" "font-#{$weight}" "font-bold"
URL Interpolation url(#{$var}) url(#{$path}/img.png) url(/assets/img.png)
Media Query @media #{$query} @media #{$mobile} @media (max-width: 768px)
At-rule Names @#{$rule} @#{$directive} Dynamic directive names
Comment Interpolation /* #{$var} */ /* v#{$version} */ /* v2.1.0 */

Example: Variable interpolation patterns

$theme: 'dark';
$side: 'left';
$size: 'large';

// Selector interpolation
.button-#{$theme} {
  background: black;
}
// Output: .button-dark { background: black; }

// Property interpolation
.box {
  margin-#{$side}: 20px;
}
// Output: .box { margin-left: 20px; }

// String interpolation
$base-path: '/assets/images';
.icon {
  background: url('#{$base-path}/icon.svg');
}

// Dynamic class generation
@each $sz in small, medium, large {
  .btn-#{$sz} {
    padding: #{$sz};
  }
}

// Media query interpolation
$breakpoint: '(min-width: 768px)';
@media #{$breakpoint} {
  .container { width: 750px; }
}

// Combining variables
$prefix: 'app';
$component: 'header';
.#{$prefix}-#{$component} {
  // .app-header
}
Note: Interpolation with #{} is required for selectors and property names, but optional for values.

2.4 Default Values with !default Flag

Concept Syntax Behavior Use Case
Default Assignment $var: value !default; Only assigns if variable is undefined or null Library/framework configuration
Already Defined $var: 10px; $var: 20px !default; $var remains 10px User overrides preserved
Undefined Variable $new: 5px !default; $new is set to 5px Provides fallback value
Null Override $var: null; $var: 5px !default; $var becomes 5px Null is treated as undefined
Import Order User vars → Library defaults User configuration takes priority Configurable frameworks
Module Config With @use...with Configure module variables Modern module system NEW

Example: !default flag usage

// _library.scss (component library)
$primary-color: blue !default;
$spacing: 8px !default;
$border-radius: 4px !default;

.button {
  background: $primary-color;
  padding: $spacing;
  border-radius: $border-radius;
}

// user-config.scss (user customization)
// Set BEFORE importing library
$primary-color: red;
$spacing: 12px;
// $border-radius not set, will use default

@import 'library';
// Result: red background, 12px padding, 4px radius

// ===================================
// Pattern: Configurable mixin
@mixin button($bg: null, $padding: null) {
  $bg: $bg or $primary-color !default;
  $padding: $padding or $spacing !default;
  
  background: $bg;
  padding: $padding;
}

// Modern module system
// _theme.scss
$color: blue !default;

// main.scss
@use 'theme' with (
  $color: red    // Override default
);
Note: !default is essential for creating configurable libraries and themeable components.

2.5 Variable Data Types (numbers, strings, colors, booleans, null)

Data Type Examples Operations Notes
Number 42, 3.14, 10px, 2em +, -, *, /, %, <, >, comparisons Can have units or be unitless
String "text", 'text', unquoted Concatenation (+), interpolation Quoted or unquoted
Color #fff, rgb(), hsl(), red Color functions (lighten, darken, mix) Multiple format support
Boolean true, false and, or, not, if/else Conditional logic
Null null Represents absence of value Omits property in output
List 1px 2px 3px, (a, b, c) List functions (nth, join, append) Space or comma separated
Map (key: value, key2: value2) Map functions (get, merge, keys) Key-value pairs
Function Reference get-function('name') First-class functions Advanced meta-programming

Example: Variable data types

// Numbers
$width: 100;                  // Unitless
$height: 50px;                // With unit
$opacity: 0.75;               // Decimal
$duration: 2s;                // Time unit

// Strings
$font-quoted: "Helvetica";    // Quoted
$font-unquoted: Arial;        // Unquoted
$path: '/assets/images';      // Path string

// Colors
$color-hex: #3498db;
$color-rgb: rgb(52, 152, 219);
$color-rgba: rgba(52, 152, 219, 0.8);
$color-hsl: hsl(204, 70%, 53%);
$color-name: blue;

// Booleans
$is-dark-mode: true;
$is-mobile: false;

// Null
$optional-border: null;       // Won't output

// Lists
$margins: 10px 20px 10px 20px;
$colors: red, green, blue;
$mixed: (1px solid black);

// Maps
$theme: (
  primary: #3498db,
  secondary: #2ecc71,
  text: #333
);

// Usage examples
.box {
  width: $width + px;         // 100px
  border: $optional-border;   // Omitted (null)
  
  @if $is-dark-mode {
    background: black;
  }
}

Type Checking Functions

Function Returns
type-of($var) Type name
unit($num) Unit as string
unitless($num) true/false

Null Behavior

  • Null values omit properties
  • Useful for conditional styles
  • Treated as undefined with !default
  • List/map operations ignore null

2.6 CSS Custom Properties vs SCSS Variables

Feature SCSS Variables ($var) CSS Custom Properties (--var)
Compilation Compiled away (preprocessor) Present in final CSS (runtime)
Syntax $variable: value; --variable: value;
Usage color: $variable; color: var(--variable);
Scope Static, compile-time Dynamic, cascade and inherit
Browser Support All (compiled to CSS) Modern browsers (IE11- not supported)
JavaScript Access Not accessible Can read/modify via JS NEW
Media Query Context Can use different values Inherits from cascade
Calculations Compile-time only Can use calc() at runtime
Fallback N/A (value required) var(--x, fallback)
Performance No runtime cost Slight runtime overhead

Example: SCSS variables vs CSS custom properties

// SCSS Variables (compile-time)
$primary: #3498db;
$spacing: 16px;

.button {
  background: $primary;        // Compiled to: background: #3498db;
  padding: $spacing;           // Compiled to: padding: 16px;
}

// CSS Custom Properties (runtime)
:root {
  --primary: #3498db;
  --spacing: 16px;
}

.button {
  background: var(--primary);  // Stays in CSS
  padding: var(--spacing);     // Can change at runtime
}

// ===================================
// Combining Both (Best Practice)
$default-primary: #3498db;

:root {
  --primary: #{$default-primary};  // SCSS sets initial value
  --spacing: 16px;
}

.button {
  background: var(--primary);
  
  // JavaScript can change:
  // element.style.setProperty('--primary', 'red');
}

// ===================================
// Theme switching with CSS variables
.theme-light {
  --bg: white;
  --text: black;
}

.theme-dark {
  --bg: black;
  --text: white;
}

.component {
  background: var(--bg);
  color: var(--text);
  // Theme switches without recompiling!
}

// SCSS variables for theme
$themes: (
  light: (bg: white, text: black),
  dark: (bg: black, text: white)
);

@each $theme, $colors in $themes {
  .theme-#{$theme} {
    --bg: #{map-get($colors, bg)};
    --text: #{map-get($colors, text)};
  }
}

When to Use Which?

Use SCSS Variables Use CSS Custom Properties
Build-time configuration Runtime theming
Calculations during compilation Dynamic value changes
Internal component logic JavaScript interaction
Mixin/function parameters User customization
Older browser support needed Modern cascade features
Note: Best practice: Use SCSS variables for compile-time values and CSS custom properties for runtime theming. Combine both for maximum flexibility.

3. Lists and Maps Data Structures

3.1 List Creation and Manipulation Functions

List Type Syntax Example Notes
Space-separated value1 value2 value3 $list: 10px 20px 30px; Most common, like CSS values
Comma-separated value1, value2, value3 $list: red, green, blue; Explicit list structure
Single Item (value,) $single: (item,); Trailing comma makes it a list
Empty List () $empty: (); Zero-length list
Parenthesized (val1, val2) $list: (a, b, c); Explicit grouping
Nested List list within list $nested: (1 2) (3 4); Multi-dimensional data
Index 1-based (not 0-based) First item is index 1 Different from JavaScript

Example: List creation patterns

// Space-separated (like margin values)
$margins: 10px 20px 10px 20px;

// Comma-separated (like font stack)
$fonts: Arial, Helvetica, sans-serif;

// Explicit parentheses
$sizes: (small, medium, large);

// Single-item list (needs trailing comma)
$single: (blue,);

// Empty list
$empty: ();

// Nested lists (matrix-like)
$grid: (1 2 3) (4 5 6) (7 8 9);

// Mixed separators (outer: space, inner: comma)
$complex: (a, b) (c, d) (e, f);

// List in variable
$colors: red blue green;
$first: nth($colors, 1);  // red
$length: length($colors);  // 3

3.2 List Functions (nth, length, append, join, index)

Function Syntax Description Example
nth() nth($list, $n) Get item at index n (1-based) nth((a, b, c), 2) → b
length() length($list) Count of items in list length((a, b, c)) → 3
append() append($list, $val, $sep) Add item to end of list append((a, b), c) → a, b, c
join() join($list1, $list2, $sep) Combine two lists join((a, b), (c, d)) → a, b, c, d
index() index($list, $value) Find position of value (or null) index((a, b, c), b) → 2
list-separator() list-separator($list) Get separator type space | comma
set-nth() set-nth($list, $n, $val) Replace item at index set-nth((a, b, c), 2, x) → a, x, c
zip() zip($lists...) Combine multiple lists into nested zip((a, b), (1, 2)) → (a 1), (b 2)
is-bracketed() is-bracketed($list) Check if list uses [] is-bracketed([a, b]) → true

Example: List function usage

$colors: red, green, blue, yellow;

// nth - Get item by index (1-based)
$first: nth($colors, 1);        // red
$last: nth($colors, -1);        // yellow (negative index)

// length - Count items
$count: length($colors);         // 4

// append - Add to end
$extended: append($colors, purple);
// → red, green, blue, yellow, purple

// append with separator
$spaced: append((a b), c, space);  // a b c
$comma: append((a b), c, comma);   // a, b, c

// join - Combine lists
$list1: (a, b);
$list2: (c, d);
$joined: join($list1, $list2);   // a, b, c, d

// index - Find position
$pos: index($colors, blue);      // 3
$not-found: index($colors, pink); // null

// set-nth - Replace item
$modified: set-nth($colors, 2, orange);
// → red, orange, blue, yellow

// zip - Combine into pairs
$names: (a, b, c);
$nums: (1, 2, 3);
$pairs: zip($names, $nums);
// → (a 1), (b 2), (c 3)

// Practical: Generate classes
$sizes: small, medium, large;
@each $size in $sizes {
  .text-#{$size} {
    font-size: nth((12px, 16px, 20px), index($sizes, $size));
  }
}
Warning: List indices are 1-based, not 0-based. nth($list, 1) gets the first item.

3.3 Map Creation and Key-Value Operations

Concept Syntax Example Notes
Map Syntax (key: value, key2: value2) $map: (primary: blue, secondary: green); Parentheses required
Key Types Any data type Strings, numbers, colors, etc. Usually strings or numbers
Value Types Any data type Including nested maps/lists Can be complex structures
Empty Map () $empty: (); Same as empty list
Quoted Keys ("key": value) Optional for most keys Required for special chars
Trailing Comma Allowed (a: 1, b: 2,) Optional but useful for git diffs

Example: Map creation and structure

// Basic map
$colors: (
  primary: #3498db,
  secondary: #2ecc71,
  danger: #e74c3c
);

// Nested map (theme system)
$theme: (
  colors: (
    text: #333,
    bg: #fff,
    accent: blue
  ),
  spacing: (
    small: 8px,
    medium: 16px,
    large: 24px
  ),
  fonts: (
    heading: 'Georgia',
    body: 'Arial'
  )
);

// Numeric keys
$breakpoints: (
  320: 'mobile',
  768: 'tablet',
  1024: 'desktop'
);

// Mixed value types
$config: (
  enabled: true,
  count: 5,
  color: red,
  sizes: (10px, 20px, 30px),
  nested: (
    deep: value
  )
);

// Empty map
$empty: ();

// Single entry (still needs parentheses)
$single: (key: value);

3.4 Map Functions (get, set, merge, remove, keys, values)

Function Syntax Description Example
map-get() map-get($map, $key) Retrieve value by key map-get((a: 1), a) → 1
map-has-key() map-has-key($map, $key) Check if key exists map-has-key((a: 1), a) → true
map-keys() map-keys($map) Get list of all keys map-keys((a: 1, b: 2)) → a, b
map-values() map-values($map) Get list of all values map-values((a: 1, b: 2)) → 1, 2
map-merge() map-merge($map1, $map2) Combine maps (shallow) map-merge((a: 1), (b: 2)) → (a: 1, b: 2)
map-remove() map-remove($map, $keys...) Remove keys from map map-remove((a: 1, b: 2), a) → (b: 2)
Deep Get NEW map.get($map, $keys...) Get nested value Use sass:map module
Deep Merge NEW map.deep-merge($map1, $map2) Recursive merge Modern module function

Example: Map function operations

$colors: (
  primary: #3498db,
  secondary: #2ecc71,
  danger: #e74c3c,
  warning: #f39c12
);

// map-get - Retrieve value
$primary: map-get($colors, primary);  // #3498db

// map-has-key - Check existence
@if map-has-key($colors, primary) {
  .btn { background: map-get($colors, primary); }
}

// map-keys - Get all keys
$color-names: map-keys($colors);
// → primary, secondary, danger, warning

// map-values - Get all values
$color-values: map-values($colors);
// → #3498db, #2ecc71, #e74c3c, #f39c12

// map-merge - Combine maps
$new-colors: (success: green, info: blue);
$all-colors: map-merge($colors, $new-colors);
// Adds success and info to existing colors

// map-remove - Delete keys
$subset: map-remove($colors, danger, warning);
// → (primary: #3498db, secondary: #2ecc71)

// ===================================
// Practical: Generate utility classes
@each $name, $color in $colors {
  .bg-#{$name} {
    background: $color;
  }
  .text-#{$name} {
    color: $color;
  }
}

// ===================================
// Modern sass:map module
@use 'sass:map';

$theme: (
  colors: (
    primary: (
      base: blue,
      light: lightblue
    )
  )
);

// Deep get (nested access)
$base-color: map.get($theme, 'colors', 'primary', 'base');
// → blue

// Deep merge
$theme2: (
  colors: (
    primary: (
      dark: darkblue
    )
  )
);
$merged: map.deep-merge($theme, $theme2);
// Recursively merges nested maps
Note: Use modern @use 'sass:map'; module for advanced operations like map.deep-merge() and map.deep-remove().

3.5 Multi-dimensional Lists and Nested Maps

Structure Syntax Access Pattern Use Case
2D List (Matrix) ((a, b), (c, d)) nth(nth($matrix, row), col) Grid layouts, tables
List of Lists (list1) (list2) (list3) Iterate outer then inner Grouped configurations
Nested Maps (key: (nested-key: val)) Multiple map-get calls Theme systems, config
Map of Lists (key: (val1, val2)) map-get then nth Multiple values per key
List of Maps ((k: v), (k: v)) nth then map-get Array of objects pattern
Deep Nesting 3+ levels Chain access functions Complex data structures

Example: Multi-dimensional data structures

// 2D List (Matrix)
$grid: (
  (1, 2, 3),
  (4, 5, 6),
  (7, 8, 9)
);

// Access: row 2, column 3
$row: nth($grid, 2);        // (4, 5, 6)
$value: nth($row, 3);       // 6

// Nested Maps (Theme System)
$theme: (
  colors: (
    primary: (
      base: #3498db,
      light: #5dade2,
      dark: #2874a6
    ),
    secondary: (
      base: #2ecc71,
      light: #58d68d,
      dark: #229954
    )
  ),
  spacing: (
    small: 8px,
    medium: 16px,
    large: 24px
  )
);

// Deep access
$colors: map-get($theme, colors);
$primary: map-get($colors, primary);
$base: map-get($primary, base);  // #3498db

// Map of Lists (Breakpoint ranges)
$breakpoints: (
  mobile: (320px, 767px),
  tablet: (768px, 1023px),
  desktop: (1024px, 1439px),
  wide: (1440px, null)
);

$tablet-range: map-get($breakpoints, tablet);
$min: nth($tablet-range, 1);  // 768px
$max: nth($tablet-range, 2);  // 1023px

// List of Maps (Menu items)
$menu: (
  (label: 'Home', url: '/', icon: 'house'),
  (label: 'About', url: '/about', icon: 'info'),
  (label: 'Contact', url: '/contact', icon: 'mail')
);

@each $item in $menu {
  $label: map-get($item, label);
  $url: map-get($item, url);
  
  .nav-#{to-lower-case($label)} {
    content: $label;
  }
}

// ===================================
// Helper function for deep access
@function deep-get($map, $keys...) {
  @each $key in $keys {
    $map: map-get($map, $key);
  }
  @return $map;
}

// Usage
$color: deep-get($theme, colors, primary, base);
// → #3498db

Example: Map Pattern

$config: (
  colors: (
    brand: #333
  ),
  sizes: (
    base: 16px
  )
);

// Access
$brand: map-get(
  map-get($config, colors),
  brand
);

Example: List of Maps Pattern

$items: (
  (name: a, val: 1),
  (name: b, val: 2),
  (name: c, val: 3)
);

// Iterate
@each $item in $items {
  $n: map-get($item, name);
  $v: map-get($item, val);
}

3.6 List and Map Iteration Patterns

Pattern Syntax Variables Use Case
Each List Item @each $item in $list $item: current value Simple iteration
Each with Index @for $i from 1 through length($list) $i: index, use nth($list, $i) Need position number
Each Map Entry @each $key, $value in $map $key, $value: pair Map iteration
Nested List @each $item in $list { @each $sub in $item } Nested loop variables Multi-dimensional data
Destructuring @each $a, $b in $list Unpack list items Paired values
Map Keys Only @each $key in map-keys($map) $key: key only Key-based operations
Map Values Only @each $val in map-values($map) $val: value only Value-based operations

Example: Iteration patterns

// Simple list iteration
$sizes: small, medium, large;

@each $size in $sizes {
  .text-#{$size} {
    font-size: $size;
  }
}

// List with index
$colors: red, green, blue;

@for $i from 1 through length($colors) {
  .color-#{$i} {
    color: nth($colors, $i);
    z-index: $i;
  }
}

// Map iteration (key-value)
$breakpoints: (
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px
);

@each $name, $width in $breakpoints {
  @media (min-width: $width) {
    .container-#{$name} {
      max-width: $width;
    }
  }
}

// Nested list iteration
$grid: (
  (1, 2, 3),
  (4, 5, 6),
  (7, 8, 9)
);

@each $row in $grid {
  @each $cell in $row {
    .cell-#{$cell} {
      order: $cell;
    }
  }
}

// List destructuring (paired values)
$pairs: (10px 1), (20px 2), (30px 3);

@each $size, $weight in $pairs {
  .combo-#{$weight} {
    font-size: $size;
    font-weight: $weight * 100;
  }
}

// Map keys iteration
@each $name in map-keys($breakpoints) {
  .visible-#{$name} {
    display: none;
    
    @media (min-width: map-get($breakpoints, $name)) {
      display: block;
    }
  }
}

// Complex: List of maps
$buttons: (
  (variant: primary, color: blue, text: white),
  (variant: secondary, color: gray, text: black),
  (variant: danger, color: red, text: white)
);

@each $btn in $buttons {
  .btn-#{map-get($btn, variant)} {
    background: map-get($btn, color);
    color: map-get($btn, text);
  }
}

// Practical: Generate utility classes
$spacings: (
  0: 0,
  1: 0.25rem,
  2: 0.5rem,
  3: 1rem,
  4: 1.5rem,
  5: 3rem
);

$sides: (
  t: top,
  r: right,
  b: bottom,
  l: left
);

@each $size-key, $size-val in $spacings {
  @each $side-key, $side-val in $sides {
    .m#{$side-key}-#{$size-key} {
      margin-#{$side-val}: $size-val;
    }
    .p#{$side-key}-#{$size-key} {
      padding-#{$side-val}: $size-val;
    }
  }
}
// Generates: mt-0, mt-1, mr-0, mr-1, pt-0, etc.

Iteration Best Practices

  • Use @each for lists when index is not needed
  • Use @each $key, $value for maps to get both
  • Use @for when you need the index/counter
  • Destructure lists when items are paired values
  • Combine map-keys() or map-values() with @each when only one is needed
  • Keep nested iterations shallow (max 2-3 levels) for readability
Note: Lists and maps are immutable. Functions like append() and map-merge() return new structures without modifying originals.

4. Mixins and Reusable Code Patterns

4.1 Mixin Definition with @mixin Directive

Concept Syntax Example Notes
Basic Mixin @mixin name { ... } @mixin reset { margin: 0; padding: 0; } Reusable style block
With Arguments @mixin name($arg) { ... } @mixin size($w) { width: $w; } Parameterized styles
Multiple Arguments @mixin name($a, $b) { ... } @mixin margin($top, $right) { ... } Multiple parameters
Default Values @mixin name($arg: default) { ... } @mixin border($w: 1px) { ... } Optional parameters
Naming Convention kebab-case or camelCase @mixin flex-center Descriptive names preferred
Scope Can use outer variables Access global/local variables Closures supported

Example: Mixin definitions

// Basic mixin without arguments
@mixin reset {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

// Mixin with single argument
@mixin border-radius($radius) {
  border-radius: $radius;
  -webkit-border-radius: $radius;
  -moz-border-radius: $radius;
}

// Mixin with multiple arguments
@mixin box-shadow($x, $y, $blur, $color) {
  box-shadow: $x $y $blur $color;
  -webkit-box-shadow: $x $y $blur $color;
  -moz-box-shadow: $x $y $blur $color;
}

// Mixin with default parameters
@mixin button($bg: blue, $color: white, $padding: 10px 20px) {
  background: $bg;
  color: $color;
  padding: $padding;
  border: none;
  cursor: pointer;
}

// Mixin accessing outer variables
$base-font-size: 16px;

@mixin responsive-font($multiplier) {
  font-size: $base-font-size * $multiplier;
}

// Complex mixin
@mixin flex-center($direction: row) {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: $direction;
}

4.2 Mixin Inclusion with @include Directive

Usage Pattern Syntax Example Notes
Basic Include @include mixin-name; @include reset; No arguments
With Arguments @include name($val); @include border-radius(5px); Positional arguments
Named Arguments @include name($arg: val); @include button($bg: red); Explicit parameter names
Mixed Arguments @include name(pos, $named: val); Positional then named Positional must come first
Nested Include Inside selectors or other mixins .btn { @include button; } Most common pattern
Top-level Include Outside selectors Generates global CSS Use cautiously

Example: Mixin inclusion patterns

// Define mixins
@mixin reset {
  margin: 0;
  padding: 0;
}

@mixin button($bg, $color, $size: medium) {
  background: $bg;
  color: $color;
  padding: if($size == small, 5px 10px, 
           if($size == medium, 10px 20px, 15px 30px));
}

// Basic inclusion
.box {
  @include reset;
  width: 100%;
}

// With positional arguments
.primary-btn {
  @include button(blue, white);
}

// With named arguments (any order)
.secondary-btn {
  @include button($color: black, $bg: gray, $size: large);
}

// Mixed positional and named
.danger-btn {
  @include button(red, white, $size: small);
}

// Multiple includes in one selector
.card {
  @include reset;
  @include border-radius(8px);
  @include box-shadow(0, 2px, 4px, rgba(0,0,0,0.1));
}

// Nested within media query
.responsive {
  width: 100%;
  
  @media (min-width: 768px) {
    @include flex-center(column);
  }
}

// Include within mixin (composition)
@mixin fancy-button {
  @include button(blue, white);
  @include border-radius(20px);
  text-transform: uppercase;
}
Note: Named arguments allow any order and improved readability for mixins with many parameters.

4.3 Mixin Arguments and Default Parameters

Feature Syntax Behavior Example
Required Argument @mixin name($arg) Must be provided @mixin size($width) { ... }
Default Value @mixin name($arg: default) Optional, uses default if omitted @mixin btn($bg: blue) { ... }
Multiple Defaults @mixin name($a: 1, $b: 2) All optional with defaults Can override selectively
Mixed Required/Optional @mixin name($req, $opt: val) Required first, then optional Best practice pattern
Null as Default @mixin name($arg: null) Can check for user override Conditional property output
Expression Defaults @mixin name($a: $var * 2) Computed default values Dynamic defaults

Example: Argument patterns and defaults

// All optional with defaults
@mixin padding($top: 10px, $right: 10px, $bottom: 10px, $left: 10px) {
  padding: $top $right $bottom $left;
}

// Usage variations
.box1 { @include padding; }  // Uses all defaults
.box2 { @include padding(20px); }  // Override first only
.box3 { @include padding($bottom: 30px); }  // Named override

// Mixed required and optional
@mixin button($text, $bg: blue, $color: white) {
  content: $text;
  background: $bg;
  color: $color;
}

.btn { @include button('Click Me'); }  // Required provided
.btn2 { @include button('Submit', green); }  // Override one optional

// Null default for conditional properties
@mixin border($width: 1px, $style: solid, $color: null) {
  border-width: $width;
  border-style: $style;
  
  @if $color != null {
    border-color: $color;
  }
}

.element {
  @include border;  // No color set
}

.element2 {
  @include border($color: red);  // Color explicitly set
}

// Expression as default
$base-size: 16px;

@mixin font($size: $base-size * 1.5, $weight: normal) {
  font-size: $size;
  font-weight: $weight;
}

// Complex default with function
@mixin box-size($width, $height: $width) {
  width: $width;
  height: $height;  // Defaults to same as width (square)
}

.square { @include box-size(100px); }  // 100px × 100px
.rect { @include box-size(100px, 50px); }  // 100px × 50px

// Boolean defaults
@mixin text($uppercase: false, $bold: false) {
  @if $uppercase {
    text-transform: uppercase;
  }
  @if $bold {
    font-weight: bold;
  }
}

.normal { @include text; }
.shouting { @include text($uppercase: true, $bold: true); }

4.4 Variadic Arguments (...) and @rest

Feature Syntax Description Use Case
Variadic Parameter @mixin name($args...) Accepts any number of arguments Flexible argument count
Rest After Required @mixin name($req, $rest...) Required + variable args At least one argument
Spread List @include name($list...) Unpack list as arguments Pass list items individually
Spread Map @include name($map...) Unpack map as named args Pass map as named parameters
Access Variadic nth($args, $n) Get specific argument Index into variadic list
Keyword Arguments keywords($args) Get named args as map Advanced meta-programming

Example: Variadic arguments and rest parameters

// Accept any number of arguments
@mixin box-shadow($shadows...) {
  box-shadow: $shadows;
  -webkit-box-shadow: $shadows;
}

// Usage with multiple shadows
.card {
  @include box-shadow(
    0 2px 4px rgba(0,0,0,0.1),
    0 4px 8px rgba(0,0,0,0.1),
    0 8px 16px rgba(0,0,0,0.1)
  );
}

// Required argument + rest
@mixin transition($property, $rest...) {
  transition: $property $rest;
}

.button {
  @include transition(background, 0.3s, ease-in-out);
  // → transition: background 0.3s ease-in-out;
}

// Spread list into arguments
@mixin margin($top, $right, $bottom, $left) {
  margin: $top $right $bottom $left;
}

$spacing: 10px 20px 10px 20px;
.box {
  @include margin($spacing...);
  // Unpacks list: margin(10px, 20px, 10px, 20px)
}

// Spread map as named arguments
@mixin button($bg, $color, $padding) {
  background: $bg;
  color: $color;
  padding: $padding;
}

$btn-config: (
  bg: blue,
  color: white,
  padding: 10px 20px
);

.btn {
  @include button($btn-config...);
  // Maps to named parameters
}

// Iterate over variadic arguments
@mixin generate-classes($prefix, $values...) {
  @each $value in $values {
    .#{$prefix}-#{$value} {
      #{$prefix}: $value;
    }
  }
}

@include generate-classes(color, red, green, blue);
// Generates: .color-red, .color-green, .color-blue

// Combined regular and variadic
@mixin flex($direction, $rest...) {
  display: flex;
  flex-direction: $direction;
  
  @if length($rest) > 0 {
    justify-content: nth($rest, 1);
  }
  @if length($rest) > 1 {
    align-items: nth($rest, 2);
  }
}

.container {
  @include flex(row, center, center);
}

// Advanced: keyword arguments
@mixin advanced($args...) {
  $named: keywords($args);
  // $named is a map of named arguments
  
  @if map-has-key($named, color) {
    color: map-get($named, color);
  }
}
Note: The ... syntax can collect arguments (in definition) or spread them (in inclusion).

4.5 Content Blocks and @content Directive

Concept Syntax Description Use Case
@content Directive @mixin name { ... @content } Inject caller's content block Wrapper mixins
Pass Content @include name { content } Provide styles to inject Custom styles within mixin
Multiple @content Multiple @content in mixin Inject same content multiple times Repetitive patterns
Content Arguments NEW @content($arg) Pass values to content block Advanced meta-programming
Using Passed Values @include name using ($var) Receive arguments in content Dynamic content generation
Empty Content @content without passed block Nothing injected (no error) Optional content blocks

Example: @content directive patterns

// Basic content injection
@mixin media-query($breakpoint) {
  @media (min-width: $breakpoint) {
    @content;
  }
}

// Usage
.sidebar {
  width: 100%;
  
  @include media-query(768px) {
    width: 300px;
    float: left;
  }
}

// Output:
// .sidebar { width: 100%; }
// @media (min-width: 768px) {
//   .sidebar { width: 300px; float: left; }
// }

// Wrapper mixin with @content
@mixin hover-focus {
  &:hover,
  &:focus {
    @content;
  }
}

.button {
  background: blue;
  
  @include hover-focus {
    background: darkblue;
    transform: scale(1.05);
  }
}

// Multiple @content (same content injected twice)
@mixin vendor-prefix {
  -webkit-@content;
  -moz-@content;
  @content;
}

// Advanced: Content with arguments (Sass 3.5+)
@mixin context($name) {
  .#{$name} {
    @content($name);
  }
}

@include context('header') using ($ctx) {
  background: #{$ctx}-color;  // header-color
}

// Media query mixin library
$breakpoints: (
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px
);

@mixin respond-to($breakpoint) {
  $value: map-get($breakpoints, $breakpoint);
  
  @media (min-width: $value) {
    @content;
  }
}

.container {
  padding: 1rem;
  
  @include respond-to(md) {
    padding: 2rem;
  }
  
  @include respond-to(lg) {
    padding: 3rem;
  }
}

// Pseudo-selector wrapper
@mixin pseudo($pseudo) {
  &:#{$pseudo} {
    @content;
  }
}

a {
  color: blue;
  
  @include pseudo(hover) {
    color: red;
  }
  
  @include pseudo(visited) {
    color: purple;
  }
}

// Context-based styling
@mixin when-inside($selector) {
  #{$selector} & {
    @content;
  }
}

.button {
  background: white;
  
  @include when-inside('.dark-theme') {
    background: black;
    color: white;
  }
}
// Output: .dark-theme .button { background: black; color: white; }

// Keyframe wrapper
@mixin keyframes($name) {
  @keyframes #{$name} {
    @content;
  }
}

@include keyframes(fade-in) {
  from { opacity: 0; }
  to { opacity: 1; }
}

Example: Without @content

@mixin reset {
  margin: 0;
  padding: 0;
}

.box {
  @include reset;
  // Just gets mixin styles
}

Example: With @content

@mixin container {
  max-width: 1200px;
  @content;
}

.main {
  @include container {
    padding: 20px;
  }
}

4.6 Dynamic Mixin Generation and Library Patterns

Pattern Technique Description Example Use
Loop-generated Mixins @each with mixin calls Generate utilities from data Spacing, color utilities
Conditional Mixins @if inside mixin Behavior based on arguments Responsive variations
Mixin Composition Mixins calling mixins Build complex from simple Component libraries
Configuration Maps Map-driven mixin logic Data-driven styling Theme systems
Mixin Libraries Reusable mixin collections Shareable across projects Framework development
Meta Mixins Mixins generating CSS rules Advanced code generation BEM, atomic CSS

Example: Dynamic mixin patterns

// Utility generator mixin
@mixin generate-spacing-utilities($property, $sides, $sizes) {
  @each $side-key, $side-value in $sides {
    @each $size-key, $size-value in $sizes {
      .#{$property}#{$side-key}-#{$size-key} {
        #{$property}-#{$side-value}: $size-value;
      }
    }
  }
}

// Usage
$sides: (t: top, r: right, b: bottom, l: left);
$sizes: (0: 0, 1: 0.25rem, 2: 0.5rem, 3: 1rem);

@include generate-spacing-utilities(margin, $sides, $sizes);
@include generate-spacing-utilities(padding, $sides, $sizes);
// Generates: mt-0, mt-1, mr-0, pt-0, etc.

// Conditional responsive mixin
@mixin responsive-font($min, $max, $min-vw: 320px, $max-vw: 1200px) {
  font-size: $min;
  
  @media (min-width: $min-vw) {
    font-size: calc(#{$min} + (#{$max} - #{$min}) * 
                    ((100vw - #{$min-vw}) / (#{$max-vw} - #{$min-vw})));
  }
  
  @media (min-width: $max-vw) {
    font-size: $max;
  }
}

// Mixin composition (building blocks)
@mixin reset {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

@mixin flex-center {
  display: flex;
  justify-content: center;
  align-items: center;
}

@mixin card-base {
  @include reset;
  border: 1px solid #ddd;
  border-radius: 4px;
  padding: 1rem;
}

@mixin card-hoverable {
  @include card-base;
  transition: transform 0.3s;
  
  &:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 8px rgba(0,0,0,0.1);
  }
}

// Map-driven button system
$button-variants: (
  primary: (bg: #007bff, color: white, hover-bg: #0056b3),
  secondary: (bg: #6c757d, color: white, hover-bg: #545b62),
  success: (bg: #28a745, color: white, hover-bg: #1e7e34),
  danger: (bg: #dc3545, color: white, hover-bg: #bd2130)
);

@mixin button-variant($variant) {
  $config: map-get($button-variants, $variant);
  
  background: map-get($config, bg);
  color: map-get($config, color);
  border: none;
  padding: 10px 20px;
  cursor: pointer;
  
  &:hover {
    background: map-get($config, hover-bg);
  }
}

// Generate all button variants
@each $name, $config in $button-variants {
  .btn-#{$name} {
    @include button-variant($name);
  }
}

// BEM generator mixin
@mixin bem-block($block) {
  .#{$block} {
    @content;
  }
}

@mixin bem-element($element) {
  &__#{$element} {
    @content;
  }
}

@mixin bem-modifier($modifier) {
  &--#{$modifier} {
    @content;
  }
}

// Usage
@include bem-block('card') {
  border: 1px solid gray;
  
  @include bem-element('header') {
    font-weight: bold;
  }
  
  @include bem-element('body') {
    padding: 1rem;
  }
  
  @include bem-modifier('featured') {
    border-color: gold;
  }
}

// Advanced: Breakpoint mixin library
$breakpoints: (
  xs: 0,
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px
);

@mixin media-up($name) {
  $min: map-get($breakpoints, $name);
  @media (min-width: $min) {
    @content;
  }
}

@mixin media-down($name) {
  $max: map-get($breakpoints, $name) - 1px;
  @media (max-width: $max) {
    @content;
  }
}

@mixin media-between($lower, $upper) {
  $min: map-get($breakpoints, $lower);
  $max: map-get($breakpoints, $upper) - 1px;
  @media (min-width: $min) and (max-width: $max) {
    @content;
  }
}

Mixin Best Practices

  • Use mixins for reusable patterns, not single properties
  • Prefer @content for wrapper patterns (media queries, pseudo-selectors)
  • Use default parameters for common use cases
  • Name mixins descriptively based on purpose, not implementation
  • Combine simple mixins into complex ones (composition)
  • Use maps and loops to generate utility classes from data
  • Document mixin parameters and expected usage
  • Keep mixins focused on single responsibility
Warning: Overusing mixins can lead to CSS bloat. Each @include duplicates styles. Consider @extend or utility classes for shared styles.

5. Functions and Built-in Function Reference

5.1 Custom Function Definition with @function

Feature Syntax Description Example
Function Definition @function name() { } Declares reusable function @function double($n) { @return $n * 2; }
@return Directive @return value; Returns computed value Must have at least one return
Parameters $param1, $param2 Function arguments Can have defaults like mixins
Function Call name($args) Invokes function width: double(10px);
Scope Variables local to function Isolated scope Local vars don't leak outside
Naming Kebab-case or camelCase Descriptive, verb-based calculate-rem(), lighten-color()

Example: Custom function basics

// Simple calculation function
@function strip-unit($number) {
  @if type-of($number) == 'number' and not unitless($number) {
    @return $number / ($number * 0 + 1);
  }
  @return $number;
}

// Usage
$value: strip-unit(16px);  // Returns: 16

// Function with multiple parameters
@function calculate-rem($size, $base: 16px) {
  $rem: $size / $base;
  @return #{$rem}rem;
}

// Usage
font-size: calculate-rem(24px);       // 1.5rem
font-size: calculate-rem(20px, 10px); // 2rem

// Conditional return
@function contrast-color($color) {
  @if (lightness($color) > 50%) {
    @return #000;
  } @else {
    @return #fff;
  }
}

.button {
  background: #3498db;
  color: contrast-color(#3498db);  // Returns: #fff
}

5.2 Function Arguments and Return Values

Feature Syntax Behavior Use Case
Required Arguments @function fn($arg) Must be provided Essential parameters
Default Arguments @function fn($arg: val) Optional with fallback Common use cases
Variadic Arguments @function fn($args...) Accept unlimited args Flexible parameters
Named Arguments fn($name: value) Explicit parameter naming Clarity, skip defaults
Return Type Any Sass data type Numbers, strings, colors, lists, maps, null Flexible output
Multiple Returns Conditional @return Branch-based returns Complex logic
Early Return @return exits function Stops execution Guard clauses

Example: Advanced function arguments

// Variadic arguments
@function sum($numbers...) {
  $total: 0;
  @each $num in $numbers {
    $total: $total + $num;
  }
  @return $total;
}

$result: sum(1, 2, 3, 4, 5);  // 15

// Named arguments for clarity
@function responsive-size(
  $min-size,
  $max-size,
  $min-viewport: 320px,
  $max-viewport: 1200px
) {
  $slope: ($max-size - $min-size) / ($max-viewport - $min-viewport);
  $intercept: $min-size - $slope * $min-viewport;
  @return calc(#{$intercept} + #{$slope * 100vw});
}

// Call with named args
font-size: responsive-size(
  $min-size: 14px,
  $max-size: 18px
);

// Guard clauses with early return
@function safe-divide($dividend, $divisor) {
  @if $divisor == 0 {
    @warn "Cannot divide by zero";
    @return null;
  }
  @return $dividend / $divisor;
}

// Return different types
@function get-spacing($key) {
  $spacing: (small: 8px, medium: 16px, large: 24px);
  
  @if map-has-key($spacing, $key) {
    @return map-get($spacing, $key);  // Returns number
  }
  @return null;  // Returns null if not found
}

5.3 Built-in Color Functions (lighten, darken, mix)

Function Syntax Description Example
lighten() lighten($color, $amount) Increases lightness by % lighten(#3498db, 20%)
darken() darken($color, $amount) Decreases lightness by % darken(#3498db, 20%)
mix() mix($c1, $c2, $weight) Blends two colors mix(#f00, #00f, 50%)
saturate() saturate($color, $amount) Increases saturation saturate(#3498db, 20%)
desaturate() desaturate($color, $amount) Decreases saturation desaturate(#3498db, 20%)
grayscale() grayscale($color) Removes all saturation grayscale(#3498db)
complement() complement($color) Returns opposite hue complement(#3498db)
invert() invert($color) Inverts RGB values invert(#3498db)
adjust-hue() adjust-hue($color, $degrees) Rotates hue on color wheel adjust-hue(#3498db, 45deg)
opacity/alpha() opacity($color) Gets alpha channel value alpha(rgba(0,0,0,0.5))
transparentize() transparentize($color, $amount) Decreases opacity transparentize(#000, 0.3)
opacify()/fade-in() opacify($color, $amount) Increases opacity opacify(rgba(0,0,0,.5), 0.2)

Example: Color manipulation functions

$primary: #3498db;

// Lightness adjustments
.light-bg {
  background: lighten($primary, 30%);  // #a8d5f2
}

.dark-bg {
  background: darken($primary, 20%);   // #1f5d87
}

// Color mixing
$brand-gradient: mix(#3498db, #9b59b6, 50%);

.gradient {
  background: linear-gradient(
    to right,
    #3498db,
    $brand-gradient,
    #9b59b6
  );
}

// Saturation
.vibrant {
  color: saturate($primary, 40%);      // More vivid
}

.muted {
  color: desaturate($primary, 40%);    // Less vivid
}

// Complementary color scheme
$accent: complement($primary);         // Opposite on color wheel

.scheme {
  background: $primary;
  color: $accent;
}

// Transparency
$overlay: transparentize(#000, 0.5);   // rgba(0, 0, 0, 0.5)

.modal-backdrop {
  background: $overlay;
}

// Advanced: Color palette generator
@function generate-palette($base-color) {
  @return (
    base: $base-color,
    light: lighten($base-color, 15%),
    lighter: lighten($base-color, 30%),
    dark: darken($base-color, 15%),
    darker: darken($base-color, 30%),
    complement: complement($base-color)
  );
}

$blue-palette: generate-palette(#3498db);
Note: Use mix() instead of lighten()/darken() for more natural color variations. Mix with white/black produces better results.

5.4 Built-in Math Functions (abs, ceil, floor, round)

Function Syntax Description Example
abs() abs($number) Absolute value abs(-15px)15px
ceil() ceil($number) Round up to nearest integer ceil(4.3)5
floor() floor($number) Round down to nearest integer floor(4.8)4
round() round($number) Round to nearest integer round(4.5)5
max() max($numbers...) Returns largest value max(1, 5, 3)5
min() min($numbers...) Returns smallest value min(1, 5, 3)1
percentage() percentage($number) Converts to percentage percentage(0.5)50%
random() random($limit) Random integer 1 to $limit random(100)1-100
comparable() comparable($n1, $n2) Check if units compatible comparable(1px, 1em)false

Example: Math function applications

// Responsive grid calculation
@function grid-width($cols, $total: 12) {
  $percent: ($cols / $total) * 100%;
  @return floor($percent * 100) / 100;  // Round to 2 decimals
}

.col-4 {
  width: grid-width(4);  // 33.33%
}

// Clamp value between min and max
@function clamp($value, $min, $max) {
  @return max($min, min($value, $max));
}

$size: clamp(20px, 10px, 30px);  // Returns: 20px

// Aspect ratio calculation
@function aspect-ratio-padding($width, $height) {
  @return percentage($height / $width);
}

.video-16-9 {
  padding-bottom: aspect-ratio-padding(16, 9);  // 56.25%
}

// Random color generator
@function random-color() {
  @return rgb(random(255), random(255), random(255));
}

.random-bg {
  background: random-color();
}

// Spacing scale with rounding
$base-spacing: 8px;

@function spacing($multiplier) {
  @return round($base-spacing * $multiplier);
}

.mt-1 { margin-top: spacing(1); }    // 8px
.mt-2 { margin-top: spacing(2); }    // 16px
.mt-3 { margin-top: spacing(3); }    // 24px

// Ensure non-negative values
@function positive($value) {
  @return max(0, $value);
}

.safe-margin {
  margin: positive(-10px);  // 0px (prevents negative)
}

5.5 String Functions (quote, unquote, str-length)

Function Syntax Description Example
quote() quote($string) Adds quotes to string quote(sans-serif)"sans-serif"
unquote() unquote($string) Removes quotes from string unquote("Arial")Arial
str-length() str-length($string) Returns character count str-length("hello")5
str-index() str-index($string, $substring) Finds position of substring str-index("hello", "ll")3
str-insert() str-insert($string, $insert, $index) Inserts string at position str-insert("hello", "X", 3)"heXllo"
str-slice() str-slice($string, $start, $end) Extracts substring str-slice("hello", 2, 4)"ell"
to-upper-case() to-upper-case($string) Converts to uppercase to-upper-case("hello")"HELLO"
to-lower-case() to-lower-case($string) Converts to lowercase to-lower-case("HELLO")"hello"
unique-id() unique-id() Generates unique string unique-id()"u1a2b3c4"

Example: String manipulation

// Font family management
$font-stack: (Helvetica, Arial, sans-serif);

@function get-font-stack($fonts) {
  $stack: '';
  @each $font in $fonts {
    @if str-index($font, ' ') {
      $stack: $stack + quote($font) + ', ';
    } @else {
      $stack: $stack + $font + ', ';
    }
  }
  @return unquote(str-slice($stack, 1, -3));
}

.text {
  font-family: get-font-stack($font-stack);
}

// String replacement function
@function str-replace($string, $search, $replace: '') {
  $index: str-index($string, $search);
  
  @if $index {
    $before: str-slice($string, 1, $index - 1);
    $after: str-slice($string, $index + str-length($search));
    @return $before + $replace + $after;
  }
  
  @return $string;
}

$url: "assets/images/icon.png";
$new-url: str-replace($url, "assets", "public");
// Result: "public/images/icon.png"

// Class name generator
@function bem-class($block, $element: null, $modifier: null) {
  $class: $block;
  
  @if $element {
    $class: $class + '__' + $element;
  }
  
  @if $modifier {
    $class: $class + '--' + $modifier;
  }
  
  @return unquote('.' + $class);
}

// Usage
#{bem-class('card', 'header', 'large')} {
  font-size: 2rem;
}
// Generates: .card__header--large { }

// Unique ID for animations
@function unique-animation-name($base) {
  @return unquote($base + '-' + unique-id());
}

$anim-name: unique-animation-name('slide');

@keyframes #{$anim-name} {
  from { opacity: 0; }
  to { opacity: 1; }
}

5.6 Type Checking Functions (type-of, unit, unitless)

Function Syntax Returns Example
type-of() type-of($value) Data type as string type-of(10px)"number"
unit() unit($number) Unit as string unit(10px)"px"
unitless() unitless($number) Boolean (has no unit) unitless(10)true
is-bracketed() is-bracketed($list) Boolean (list has [ ]) is-bracketed([a, b])true
is-superselector() is-superselector($s1, $s2) Boolean (s1 contains s2) is-superselector('.a .b', '.b')
variable-exists() variable-exists($name) Boolean (var defined) variable-exists(color)
global-variable-exists() global-variable-exists($name) Boolean (global var exists) Checks global scope only
function-exists() function-exists($name) Boolean (function defined) function-exists(lighten)
mixin-exists() mixin-exists($name) Boolean (mixin defined) mixin-exists(clearfix)

Example: Type checking and validation

// Robust unit conversion
@function convert-to-rem($value, $base: 16px) {
  // Type validation
  @if type-of($value) != 'number' {
    @warn "#{$value} is not a number";
    @return $value;
  }
  
  // Check if already unitless or rem
  @if unitless($value) {
    @return #{$value}rem;
  }
  
  @if unit($value) == 'rem' {
    @return $value;
  }
  
  @if unit($value) == 'px' {
    @return $value / $base * 1rem;
  }
  
  @warn "Cannot convert #{unit($value)} to rem";
  @return $value;
}

.text {
  font-size: convert-to-rem(18px);      // 1.125rem
  padding: convert-to-rem(16);          // 16rem
  margin: convert-to-rem(1.5rem);       // 1.5rem
}

// Polymorphic spacing function
@function spacing($value) {
  @if type-of($value) == 'number' {
    @return $value * 8px;
  }
  
  @if type-of($value) == 'string' {
    $map: (xs: 4px, sm: 8px, md: 16px, lg: 24px, xl: 32px);
    @if map-has-key($map, $value) {
      @return map-get($map, $value);
    }
  }
  
  @warn "Invalid spacing value: #{$value}";
  @return 0;
}

.component {
  margin: spacing(2);       // 16px (number)
  padding: spacing('lg');   // 24px (string)
}

// Conditional mixin application
@mixin apply-if-exists($mixin-name, $args...) {
  @if mixin-exists($mixin-name) {
    @include #{$mixin-name}($args...);
  } @else {
    @warn "Mixin #{$mixin-name} does not exist";
  }
}

// Safe variable getter
@function get-var($name, $fallback: null) {
  @if global-variable-exists($name) {
    @return #{$name};
  }
  @return $fallback;
}

// Type guard for lists
@function safe-nth($list, $index, $default: null) {
  @if type-of($list) != 'list' {
    @return $default;
  }
  
  @if $index <= length($list) and $index > 0 {
    @return nth($list, $index);
  }
  
  @return $default;
}

$colors: red, blue, green;
$color: safe-nth($colors, 5, black);  // Returns: black (fallback)

Function Best Practices

  • Use functions for calculations, mixins for styles
  • Always validate input types and return appropriate values
  • Provide meaningful @warn/@error messages for debugging
  • Use @return early for guard clauses and error handling
  • Document expected parameters and return types
  • Keep functions pure (no side effects, same input = same output)
  • Name functions with verbs (calculate-, get-, is-, has-)
  • Combine type checking with default parameters for robustness
Note: Modern Sass (Dart Sass) uses sass:math, sass:color, sass:string modules. Use @use "sass:math"; and math.floor() instead of global functions.

6. Control Flow and Conditional Logic

6.1 @if, @else if, @else Conditional Statements

Directive Syntax Description Use Case
@if @if condition { } Executes if condition is true Basic conditional logic
@else if @else if condition { } Alternative condition Multiple conditions
@else @else { } Fallback when all conditions false Default behavior
Truthy Values All except false and null Everything else evaluates to true 0, "", empty lists are truthy
Comparison Operators ==, !=, <, >, <=, >= Compare values Numeric/string comparisons
Logical Operators and, or, not Combine conditions Complex logic
Nested Conditions @if within @if Multi-level logic Complex decision trees

Example: Conditional statements in action

// Basic @if
$theme: dark;

.header {
  @if $theme == dark {
    background: #333;
    color: #fff;
  }
}

// @if / @else if / @else chain
@mixin button-size($size) {
  @if $size == small {
    padding: 4px 8px;
    font-size: 12px;
  } @else if $size == medium {
    padding: 8px 16px;
    font-size: 14px;
  } @else if $size == large {
    padding: 12px 24px;
    font-size: 16px;
  } @else {
    padding: 8px 16px;  // Default
    font-size: 14px;
  }
}

.btn-sm { @include button-size(small); }
.btn-lg { @include button-size(large); }

// Logical operators
$mobile: true;
$tablet: false;

.responsive {
  @if $mobile and not $tablet {
    width: 100%;
  }
}

// Comparison operators
@function get-font-weight($level) {
  @if $level > 700 {
    @return 900;
  } @else if $level > 500 {
    @return 700;
  } @else if $level > 300 {
    @return 400;
  } @else {
    @return 300;
  }
}

// Complex nested conditions
@mixin responsive-text($breakpoint, $emphasize: false) {
  @if $breakpoint == mobile {
    font-size: 14px;
    
    @if $emphasize {
      font-weight: 600;
      line-height: 1.4;
    }
  } @else if $breakpoint == tablet {
    font-size: 16px;
    
    @if $emphasize {
      font-weight: 700;
      line-height: 1.5;
    }
  }
}

// Truthy/Falsy checks
$config: null;

.component {
  @if $config {
    // This won't execute (null is falsy)
    margin: $config;
  } @else {
    margin: 1rem;  // Default
  }
}
Warning: In Sass, 0, "", and () are truthy. Only false and null are falsy.

6.2 @for Loop with from/through and to Syntax

Syntax Range Description Example
@for...through @for $i from 1 through 5 Inclusive end (1, 2, 3, 4, 5) Most common usage
@for...to @for $i from 1 to 5 Exclusive end (1, 2, 3, 4) Excludes last value
Loop Variable $i, $index, etc. Current iteration value Use in calculations
Ascending Start < End Counts up 1 through 10
Descending Start > End Counts down 10 through 1
Interpolation #{$i} Use variable in selectors/properties Dynamic class generation
Nested Loops @for within @for Multi-dimensional iteration Grid generation

Example: @for loop applications

// through vs to comparison
@for $i from 1 through 3 {
  .item-#{$i} { order: $i; }
}
// Generates: .item-1, .item-2, .item-3

@for $i from 1 to 3 {
  .col-#{$i} { width: $i * 10%; }
}
// Generates: .col-1, .col-2 (excludes 3)

// Utility classes generation
@for $i from 1 through 12 {
  .col-#{$i} {
    width: percentage($i / 12);
  }
}
// Generates: .col-1 through .col-12

// Spacing scale
$base-spacing: 4px;

@for $i from 1 through 10 {
  .mt-#{$i} { margin-top: $base-spacing * $i; }
  .mb-#{$i} { margin-bottom: $base-spacing * $i; }
  .ml-#{$i} { margin-left: $base-spacing * $i; }
  .mr-#{$i} { margin-right: $base-spacing * $i; }
}
// Generates: .mt-1 to .mt-10, etc.

// Z-index layers
@for $i from 1 through 5 {
  .layer-#{$i} {
    z-index: $i * 100;
  }
}

// Font size scale
@for $i from 1 through 6 {
  h#{$i} {
    font-size: (7 - $i) * 0.25rem + 1rem;
  }
}
// h1: 2.5rem, h2: 2.25rem, ..., h6: 1.25rem

// Descending loop
@for $i from 5 through 1 {
  .priority-#{$i} {
    opacity: $i * 0.2;
  }
}

// Nested loops for grid
@for $row from 1 through 3 {
  @for $col from 1 through 4 {
    .grid-#{$row}-#{$col} {
      grid-area: $row / $col;
    }
  }
}

// Animation delays
@for $i from 1 through 5 {
  .fade-in:nth-child(#{$i}) {
    animation-delay: #{$i * 0.1}s;
  }
}

6.3 @each Loop for Lists and Maps Iteration

Syntax Use Case Example Notes
List Iteration @each $item in $list Iterate over list values Single variable
Map Iteration @each $key, $value in $map Iterate over key-value pairs Two variables
Multiple Assignment @each $a, $b in $list Destructure list items For nested lists
Variable Scope Loop variable local to loop $item only exists in @each No leakage
Nested @each @each within @each Multi-level iteration Complex data structures
Interpolation #{$var} Use in selectors/properties Dynamic generation

Example: @each loop patterns

// Simple list iteration
$colors: red, green, blue, yellow;

@each $color in $colors {
  .text-#{$color} {
    color: $color;
  }
}
// Generates: .text-red, .text-green, etc.

// Map iteration (most common)
$theme-colors: (
  primary: #007bff,
  secondary: #6c757d,
  success: #28a745,
  danger: #dc3545,
  warning: #ffc107,
  info: #17a2b8
);

@each $name, $color in $theme-colors {
  .btn-#{$name} {
    background-color: $color;
    border-color: darken($color, 10%);
    
    &:hover {
      background-color: darken($color, 10%);
    }
  }
  
  .text-#{$name} { color: $color; }
  .bg-#{$name} { background-color: $color; }
}

// Multiple assignment (destructuring)
$icons: (
  ('home', '\f015'),
  ('user', '\f007'),
  ('search', '\f002'),
  ('settings', '\f013')
);

@each $name, $code in $icons {
  .icon-#{$name}::before {
    content: $code;
    font-family: 'Font Awesome';
  }
}

// Breakpoint generation
$breakpoints: (
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px
);

@each $name, $width in $breakpoints {
  @media (min-width: $width) {
    .container {
      max-width: $width - 12px;
    }
  }
}

// Social media colors
$social: (
  facebook: #3b5998,
  twitter: #1da1f2,
  instagram: #e1306c,
  linkedin: #0077b5
);

@each $platform, $color in $social {
  .btn-#{$platform} {
    background: $color;
    color: white;
    
    &:hover {
      background: darken($color, 15%);
    }
  }
}

// Nested @each for comprehensive utilities
$spacing-sides: (t: top, r: right, b: bottom, l: left);
$spacing-values: (0: 0, 1: 4px, 2: 8px, 3: 16px, 4: 24px);

@each $side-key, $side-name in $spacing-sides {
  @each $size-key, $size-value in $spacing-values {
    .m#{$side-key}-#{$size-key} {
      margin-#{$side-name}: $size-value;
    }
    .p#{$side-key}-#{$size-key} {
      padding-#{$side-name}: $size-value;
    }
  }
}
// Generates: .mt-0, .mt-1, .pt-0, .pr-1, etc.

// Complex example: Button variants
$button-variants: (
  primary: (bg: #007bff, text: white, hover: #0056b3),
  secondary: (bg: #6c757d, text: white, hover: #545b62),
  outline: (bg: transparent, text: #007bff, hover: #007bff)
);

@each $variant, $props in $button-variants {
  .btn-#{$variant} {
    background: map-get($props, bg);
    color: map-get($props, text);
    
    &:hover {
      background: map-get($props, hover);
    }
  }
}

6.4 @while Loop for Complex Iterations

Feature Syntax Description Use Case
Basic Syntax @while condition { } Loops while condition true Unknown iteration count
Condition Check Before each iteration Exit when false Prevents infinite loops
Manual Increment Must update counter manually No automatic incrementing Custom step sizes
Infinite Loop Risk If condition never false Will hang compilation Always ensure exit condition
Use Over @for When logic is complex Dynamic termination Calculations, recursion alternatives
Less Common @for/@each preferred More predictable Use sparingly

Example: @while loop use cases

// Basic @while loop
$i: 1;

@while $i <= 5 {
  .item-#{$i} {
    width: 20% * $i;
  }
  $i: $i + 1;  // Manual increment required
}

// Fibonacci sequence generation
$fib-count: 10;
$fib-prev: 0;
$fib-curr: 1;
$i: 1;

@while $i <= $fib-count {
  .fib-#{$i} {
    width: #{$fib-curr}px;
  }
  
  $fib-next: $fib-prev + $fib-curr;
  $fib-prev: $fib-curr;
  $fib-curr: $fib-next;
  $i: $i + 1;
}

// Powers of 2 for grid columns
$col: 1;
$max: 16;

@while $col <= $max {
  .col-#{$col} {
    width: percentage($col / $max);
  }
  $col: $col * 2;  // 1, 2, 4, 8, 16
}

// Dynamic spacing based on golden ratio
$size: 1rem;
$ratio: 1.618;
$count: 1;

@while $size < 5rem {
  .spacing-#{$count} {
    margin: $size;
  }
  $size: $size * $ratio;
  $count: $count + 1;
}

// String processing (finding position)
@function find-and-mark($string, $target) {
  $i: 1;
  $result: ();
  
  @while $i <= str-length($string) {
    @if str-slice($string, $i, $i) == $target {
      $result: append($result, $i);
    }
    $i: $i + 1;
  }
  
  @return $result;
}

// Recursive-style calculation with @while
@function factorial($n) {
  $result: 1;
  $i: $n;
  
  @while $i > 1 {
    $result: $result * $i;
    $i: $i - 1;
  }
  
  @return $result;
}

.component {
  animation-duration: #{factorial(4)}ms;  // 24ms
}
Warning: Always ensure @while loops have a guaranteed exit condition. Infinite loops will freeze compilation.

6.5 Conditional Logic Best Practices and Performance

Best Practice Recommendation Reason Example
Prefer @each over @for Use @each for data iteration More readable, semantic Maps, lists of values
Guard Clauses Early return/exit Reduces nesting @if error, @return early
Limit Loop Iterations Keep under 100 iterations Compilation speed Large loops = slow builds
Avoid @while Use @for/@each when possible More predictable Known iteration counts
Cache Calculations Store in variables Avoid redundant computation Reuse map lookups
Specific Conditions Most specific @if first Early exit optimization Edge cases before general
Flat Conditionals Avoid deep nesting Readability Max 2-3 levels deep
Type Checking Validate before operations Prevent errors Check type-of first

Example: Best practices demonstration

// ❌ Bad: Deep nesting
@mixin button-bad($size, $variant, $disabled) {
  @if $size == large {
    @if $variant == primary {
      @if $disabled {
        // Too deep!
      }
    }
  }
}

// ✅ Good: Guard clauses and flat structure
@mixin button-good($size, $variant, $disabled) {
  // Guard clause - exit early
  @if $disabled {
    opacity: 0.5;
    pointer-events: none;
    @return;
  }
  
  // Flat conditions
  @if $size == large {
    padding: 12px 24px;
  }
  
  @if $variant == primary {
    background: blue;
  }
}

// ✅ Good: Cache repeated lookups
@mixin theme-styles($theme-name) {
  $theme: map-get($themes, $theme-name);  // Cache once
  
  @if $theme {
    background: map-get($theme, bg);
    color: map-get($theme, text);
  }
}

// ❌ Bad: Repeated lookups
@mixin theme-styles-bad($theme-name) {
  background: map-get(map-get($themes, $theme-name), bg);
  color: map-get(map-get($themes, $theme-name), text);
  // Looks up theme twice!
}

// ✅ Good: Specific conditions first
@function get-spacing($size) {
  // Edge cases first
  @if $size == 0 {
    @return 0;
  }
  
  @if $size < 0 {
    @warn "Negative spacing not allowed";
    @return 0;
  }
  
  // General case
  @return $size * 8px;
}

// ✅ Good: Type checking
@function safe-divide($a, $b) {
  @if type-of($a) != 'number' or type-of($b) != 'number' {
    @warn "Both arguments must be numbers";
    @return null;
  }
  
  @if $b == 0 {
    @warn "Cannot divide by zero";
    @return null;
  }
  
  @return $a / $b;
}

// ✅ Good: Prefer @each over @for for data
$sizes: (sm: 12px, md: 16px, lg: 20px);

// Preferred
@each $name, $size in $sizes {
  .text-#{$name} { font-size: $size; }
}

// Less preferred (but valid)
@for $i from 1 through length($sizes) {
  // More complex to access
}

6.6 Dynamic CSS Generation with Control Flow

Pattern Technique Output Use Case
Utility Classes @each over map Margin/padding utilities Atomic CSS frameworks
Theme Variants @each for color schemes Component color variants Design systems
Responsive Grids @for/@each for columns Grid column classes Layout systems
Animation Sequences @for with delays Staggered animations List animations
Breakpoint Utilities Nested @each Responsive utilities Mobile-first design
Color Scales @for with functions Tint/shade variations Palette generation
State Variations @if for states Hover/active/disabled Interactive components

Example: Complete utility generation system

// Comprehensive spacing utility generator
$spacing-scale: (
  0: 0,
  1: 0.25rem,
  2: 0.5rem,
  3: 0.75rem,
  4: 1rem,
  5: 1.5rem,
  6: 2rem,
  8: 3rem,
  10: 4rem
);

$spacing-properties: (
  m: margin,
  p: padding
);

$spacing-directions: (
  t: top,
  r: right,
  b: bottom,
  l: left,
  x: (left, right),
  y: (top, bottom)
);

@each $prop-abbr, $prop in $spacing-properties {
  @each $dir-abbr, $directions in $spacing-directions {
    @each $size-key, $size-value in $spacing-scale {
      .#{$prop-abbr}#{$dir-abbr}-#{$size-key} {
        @if type-of($directions) == 'list' {
          @each $dir in $directions {
            #{$prop}-#{$dir}: $size-value;
          }
        } @else {
          #{$prop}-#{$directions}: $size-value;
        }
      }
    }
  }
  
  // All sides
  @each $size-key, $size-value in $spacing-scale {
    .#{$prop-abbr}-#{$size-key} {
      #{$prop}: $size-value;
    }
  }
}
// Generates: .mt-0, .mt-1, .px-2, .m-4, etc.

// Responsive grid system with breakpoints
$grid-columns: 12;
$breakpoints: (
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px
);

// Base grid (mobile-first)
@for $i from 1 through $grid-columns {
  .col-#{$i} {
    width: percentage($i / $grid-columns);
  }
}

// Responsive variants
@each $bp-name, $bp-value in $breakpoints {
  @media (min-width: $bp-value) {
    @for $i from 1 through $grid-columns {
      .col-#{$bp-name}-#{$i} {
        width: percentage($i / $grid-columns);
      }
    }
  }
}
// Generates: .col-1 to .col-12, .col-md-1 to .col-md-12, etc.

// Color palette with tints and shades
$brand-colors: (
  primary: #3498db,
  secondary: #2ecc71,
  accent: #e74c3c
);

@each $name, $color in $brand-colors {
  .bg-#{$name} { background: $color; }
  .text-#{$name} { color: $color; }
  .border-#{$name} { border-color: $color; }
  
  // Generate tints (lighter)
  @for $i from 1 through 5 {
    $amount: $i * 10%;
    .bg-#{$name}-light-#{$i} {
      background: mix(white, $color, $amount);
    }
  }
  
  // Generate shades (darker)
  @for $i from 1 through 5 {
    $amount: $i * 10%;
    .bg-#{$name}-dark-#{$i} {
      background: mix(black, $color, $amount);
    }
  }
}

// Staggered animation system
@for $i from 1 through 10 {
  .fade-in-item:nth-child(#{$i}) {
    animation: fadeIn 0.5s ease-in;
    animation-delay: #{$i * 0.1}s;
    animation-fill-mode: both;
  }
}

// State-based component generator
@mixin generate-button-states($bg-color, $text-color) {
  background: $bg-color;
  color: $text-color;
  border: 1px solid darken($bg-color, 10%);
  
  &:hover {
    background: darken($bg-color, 8%);
  }
  
  &:active {
    background: darken($bg-color, 12%);
  }
  
  &:disabled {
    background: desaturate($bg-color, 50%);
    opacity: 0.6;
    cursor: not-allowed;
  }
  
  &:focus {
    outline: 2px solid $bg-color;
    outline-offset: 2px;
  }
}

$button-themes: (
  primary: (#007bff, white),
  success: (#28a745, white),
  danger: (#dc3545, white)
);

@each $variant, $colors in $button-themes {
  .btn-#{$variant} {
    @include generate-button-states(nth($colors, 1), nth($colors, 2));
  }
}

Control Flow Summary

  • Use @if/@else for conditional logic and branching
  • @for is best for numeric sequences with known ranges
  • @each is ideal for iterating over data (maps, lists)
  • @while for complex conditions, but use sparingly
  • Combine loops with functions for powerful generators
  • Keep iterations under 100 for optimal compilation performance
  • Use guard clauses and early returns to reduce nesting
  • Cache lookups and calculations to avoid redundant operations
Note: Control flow happens at compile time, not runtime. The generated CSS is static. For runtime logic, use CSS custom properties and JavaScript.

7. Extends and Inheritance Patterns

7.1 %Placeholder Selectors and Silent Classes

Feature Syntax Behavior Use Case
Placeholder Selector %placeholder-name Define but don't output to CSS Shared styles for @extend only
Silent Class Never appears in compiled CSS Only exists when extended Avoid unused CSS bloat
Extension @extend %placeholder; Copies selector to placeholder rules Share styles without duplication
No Output Unused placeholders removed Tree-shaken automatically Clean compiled CSS
Naming Convention Prefix with % Clear distinction from classes Intent communication
Scope Global by default Available anywhere in import tree Shared utilities
Private Placeholders %-private (with dash) Module-private in modern Sass Internal-only styles

Example: Placeholder selectors in practice

// Define placeholder (not output to CSS)
%button-base {
  display: inline-block;
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  text-align: center;
  transition: all 0.3s;
  
  &:hover {
    transform: translateY(-2px);
  }
}

// Extend the placeholder
.btn-primary {
  @extend %button-base;
  background: #007bff;
  color: white;
}

.btn-secondary {
  @extend %button-base;
  background: #6c757d;
  color: white;
}

// CSS Output:
// .btn-primary, .btn-secondary {
//   display: inline-block;
//   padding: 10px 20px;
//   ...
// }
// .btn-primary:hover, .btn-secondary:hover {
//   transform: translateY(-2px);
// }
// .btn-primary { background: #007bff; color: white; }
// .btn-secondary { background: #6c757d; color: white; }

// Card component placeholders
%card-base {
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  padding: 1rem;
}

%card-hover {
  &:hover {
    box-shadow: 0 4px 8px rgba(0,0,0,0.2);
    transform: translateY(-2px);
  }
}

.product-card {
  @extend %card-base;
  @extend %card-hover;
  
  .title {
    font-size: 1.25rem;
    font-weight: 600;
  }
}

.user-card {
  @extend %card-base;
  // No hover effect for user cards
  
  .avatar {
    width: 50px;
    height: 50px;
    border-radius: 50%;
  }
}

// Clearfix placeholder (classic example)
%clearfix {
  &::after {
    content: "";
    display: table;
    clear: both;
  }
}

.container {
  @extend %clearfix;
  width: 100%;
}

// Text truncation placeholder
%text-truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.truncated-title {
  @extend %text-truncate;
  max-width: 200px;
}
Note: Placeholders are only output if extended. If never used, they produce zero CSS, making them perfect for library code.

7.2 @extend Directive and Inheritance Chains

Concept Syntax Behavior Example
Basic Extend @extend .class; Adds selector to existing rules .btn { @extend .base; }
Extend Placeholder @extend %placeholder; Extends silent class Preferred method
Selector Grouping Combines selectors DRY compiled output .a, .b { rules }
Inheritance Chain A extends B extends C Transitive extension Multi-level inheritance
Complex Selectors Extends compound selectors All variations included .parent .child extended
Context Preservation Maintains selector context Pseudo-classes/elements preserved :hover, ::before
!optional Flag @extend .class !optional; Don't error if not found Conditional extension

Example: @extend directive usage

// Basic extension
.message {
  padding: 10px;
  border: 1px solid #ccc;
  border-radius: 4px;
}

.message-success {
  @extend .message;
  border-color: green;
  background: #d4edda;
}

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

// Compiled CSS:
// .message, .message-success, .message-error {
//   padding: 10px;
//   border: 1px solid #ccc;
//   border-radius: 4px;
// }
// .message-success { border-color: green; background: #d4edda; }
// .message-error { border-color: red; background: #f8d7da; }

// Inheritance chain
%base-button {
  display: inline-block;
  padding: 8px 16px;
  border: none;
  cursor: pointer;
}

%primary-button {
  @extend %base-button;
  background: #007bff;
  color: white;
}

.cta-button {
  @extend %primary-button;  // Gets both %primary-button AND %base-button
  font-size: 1.2rem;
  font-weight: bold;
}

// Complex selector extension
.error {
  color: red;
  
  &:hover {
    color: darkred;
  }
  
  &::before {
    content: '⚠ ';
  }
}

.validation-error {
  @extend .error;  // Gets all .error rules including :hover and ::before
  font-size: 0.875rem;
}

// Compiled output includes:
// .error, .validation-error { color: red; }
// .error:hover, .validation-error:hover { color: darkred; }
// .error::before, .validation-error::before { content: '⚠ '; }

// Optional extension (no error if not found)
.special-button {
  @extend .button-base !optional;  // Won't error if .button-base doesn't exist
  background: purple;
}

// Nested context preservation
.sidebar {
  .widget {
    padding: 1rem;
    background: white;
  }
}

.dashboard {
  .panel {
    @extend .widget;  // Becomes: .sidebar .panel { ... }
  }
}

// Multiple extends in one selector
.alert {
  @extend %card-base;
  @extend %shadow;
  @extend %rounded;
  
  padding: 1rem;
  margin: 1rem 0;
}
Warning: Extending complex selectors can create unexpected selector combinations. Prefer extending placeholders or simple classes.

7.3 @extend vs @include Performance Comparison

Aspect @extend @include (Mixin) Winner
CSS Output Size Smaller (selector grouping) Larger (duplicated rules) @extend
Gzip Compression Less effective (varied selectors) More effective (repeated rules) @include
HTTP/2 Impact Minimal difference Minimal difference Neutral
Flexibility Static (no parameters) Dynamic (accepts arguments) @include
Predictability Complex selector generation Predictable output @include
Debugging Harder (grouped selectors) Easier (local rules) @include
Browser Performance Slightly faster (fewer rules) Negligible difference Minimal impact
Maintenance Fragile (cascading changes) Isolated (local changes) @include
Modern Recommendation Use sparingly Preferred approach @include

Example: Output size comparison

// Using @extend
%button-base {
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  font-size: 14px;
  cursor: pointer;
}

.btn-primary { @extend %button-base; background: blue; }
.btn-secondary { @extend %button-base; background: gray; }
.btn-success { @extend %button-base; background: green; }

// CSS Output (Smaller - 8 lines):
// .btn-primary, .btn-secondary, .btn-success {
//   padding: 10px 20px;
//   border: none;
//   border-radius: 4px;
//   font-size: 14px;
//   cursor: pointer;
// }
// .btn-primary { background: blue; }
// .btn-secondary { background: gray; }
// .btn-success { background: green; }

// Using @include
@mixin button-base {
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  font-size: 14px;
  cursor: pointer;
}

.btn-primary { @include button-base; background: blue; }
.btn-secondary { @include button-base; background: gray; }
.btn-success { @include button-base; background: green; }

// CSS Output (Larger - 18 lines, but more predictable):
// .btn-primary {
//   padding: 10px 20px;
//   border: none;
//   border-radius: 4px;
//   font-size: 14px;
//   cursor: pointer;
//   background: blue;
// }
// .btn-secondary {
//   padding: 10px 20px;
//   border: none;
//   border-radius: 4px;
//   font-size: 14px;
//   cursor: pointer;
//   background: gray;
// }
// .btn-success {
//   padding: 10px 20px;
//   border: none;
//   border-radius: 4px;
//   font-size: 14px;
//   cursor: pointer;
//   background: green;
// }

// File size comparison (uncompressed):
// @extend: ~250 bytes
// @include: ~450 bytes

// File size comparison (gzipped):
// @extend: ~180 bytes (less compression)
// @include: ~190 bytes (better compression due to repetition)
// Difference: Negligible (~10 bytes)

// Flexibility comparison:
// ❌ @extend - cannot accept parameters
%card {
  padding: 1rem;
  border-radius: 4px;
}

// ✅ @include - dynamic parameters
@mixin card($padding: 1rem, $radius: 4px) {
  padding: $padding;
  border-radius: $radius;
}

.small-card { @include card(0.5rem, 2px); }
.large-card { @include card(2rem, 8px); }

When to Use Each

  • Use @extend: Shared static styles, semantic relationships, minimal variations
  • Use @include: Dynamic styles with parameters, predictable output, maintainability priority
  • Modern preference: @include for most cases due to flexibility and maintainability
  • Performance difference is negligible in real-world applications

7.4 Multiple Inheritance and Selector Optimization

Pattern Technique Output Consideration
Multiple Extends Multiple @extend in one selector Selector added to all extended rules Clean and efficient
Chained Extension A extends B, B extends C Transitive inheritance Hierarchical relationships
Selector Explosion Many selectors extending same base Long selector lists Monitor output size
Compound Selectors Extending complex selectors Multiple combined selectors Can be unpredictable
Smart Unification Sass merges related selectors Optimized grouping Automatic optimization
Specificity Control Extends don't add specificity Same specificity as extended CSS cascade friendly

Example: Multiple inheritance patterns

// Multiple extends in one selector
%flex-center {
  display: flex;
  justify-content: center;
  align-items: center;
}

%rounded {
  border-radius: 8px;
}

%shadow {
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.modal {
  @extend %flex-center;
  @extend %rounded;
  @extend %shadow;
  
  padding: 2rem;
  background: white;
}

// Chained extension
%base-element {
  margin: 0;
  padding: 0;
}

%interactive-element {
  @extend %base-element;
  cursor: pointer;
  user-select: none;
}

%button-element {
  @extend %interactive-element;
  border: none;
  background: transparent;
}

.custom-button {
  @extend %button-element;  // Gets all three: base, interactive, and button
  color: blue;
}

// Selector optimization in action
%card {
  background: white;
  padding: 1rem;
}

.product-card { @extend %card; }
.user-card { @extend %card; }
.info-card { @extend %card; }
.alert-card { @extend %card; }
.promo-card { @extend %card; }

// Compiled output (optimized):
// .product-card, .user-card, .info-card, .alert-card, .promo-card {
//   background: white;
//   padding: 1rem;
// }

// Smart unification example
.parent {
  .child {
    color: blue;
  }
}

.container {
  .item {
    @extend .child;  // Creates: .parent .container .item { color: blue; }
  }
}

// Compound selector extension (caution!)
.nav {
  li {
    a {
      color: blue;
      
      &:hover {
        color: darkblue;
      }
    }
  }
}

.sidebar {
  .link {
    @extend a;  // Complex output, multiple selector variations generated
  }
}

// Better approach - use placeholder
%link-styles {
  color: blue;
  
  &:hover {
    color: darkblue;
  }
}

.nav li a {
  @extend %link-styles;
}

.sidebar .link {
  @extend %link-styles;
}

// Compiled: .nav li a, .sidebar .link { color: blue; }
//           .nav li a:hover, .sidebar .link:hover { color: darkblue; }

7.5 @extend Limitations and Anti-patterns

Limitation Issue Impact Solution
Media Query Restriction Cannot extend across @media Compilation error Use mixins instead
Directive Boundary Cannot extend outside directive Scope limitations Define placeholders globally
No Parameters Static only, no variables Inflexible Use @include for dynamic
Selector Explosion Too many extends creates huge lists Large CSS output Limit extends per placeholder
Complex Selectors Unpredictable output Debugging difficulty Extend simple selectors only
Cascade Issues Order-dependent behavior Maintenance complexity Document dependencies
Cannot Extend Itself Circular extension error Compilation fails Review inheritance chain

Example: Common anti-patterns and solutions

// ❌ ANTI-PATTERN: Extending across media queries
%mobile-text {
  font-size: 14px;
}

@media (min-width: 768px) {
  .heading {
    @extend %mobile-text;  // ERROR: Cannot extend outside @media
  }
}

// ✅ SOLUTION: Use mixin
@mixin mobile-text {
  font-size: 14px;
}

@media (min-width: 768px) {
  .heading {
    @include mobile-text;  // Works!
  }
}

// ❌ ANTI-PATTERN: Extending complex nested selectors
.nav {
  ul {
    li {
      a {
        color: blue;
      }
    }
  }
}

.footer {
  .link {
    @extend a;  // Generates: .nav ul li .footer .link (confusing!)
  }
}

// ✅ SOLUTION: Use placeholder with simple selector
%link-base {
  color: blue;
}

.nav ul li a {
  @extend %link-base;
}

.footer .link {
  @extend %link-base;
}

// ❌ ANTI-PATTERN: Overusing extends (selector explosion)
%button {
  padding: 10px;
}

// 50+ selectors extending %button
.btn-1 { @extend %button; }
.btn-2 { @extend %button; }
// ... 50 more
.btn-50 { @extend %button; }

// Output: .btn-1, .btn-2, ..., .btn-50 { padding: 10px; }
// (creates very long selector lists)

// ✅ SOLUTION: Use utility class directly in HTML
.btn { padding: 10px; }
// HTML: <div class="btn btn-1">

// ❌ ANTI-PATTERN: Circular extension
%a {
  @extend %b;
}

%b {
  @extend %a;  // ERROR: Circular extension
}

// ❌ ANTI-PATTERN: Extending from multiple unrelated hierarchies
.component1 {
  .inner {
    color: red;
  }
}

.component2 {
  .section {
    .inner {
      background: blue;
    }
  }
}

.my-element {
  @extend .inner;  // Which .inner? Ambiguous!
}

// ✅ SOLUTION: Use explicit placeholders
%red-text {
  color: red;
}

%blue-background {
  background: blue;
}

.component1 .inner { @extend %red-text; }
.component2 .section .inner { @extend %blue-background; }
.my-element { @extend %red-text; }

// ❌ ANTI-PATTERN: Extending instead of composition
.button {
  padding: 10px;
  border: none;
}

.primary-button {
  @extend .button;
  background: blue;
}

.large-primary-button {
  @extend .primary-button;  // Deep inheritance chain
  font-size: 1.5rem;
}

// ✅ SOLUTION: Composition over inheritance
.button { padding: 10px; border: none; }
.button-primary { background: blue; }
.button-large { font-size: 1.5rem; }

// HTML: <button class="button button-primary button-large">
Warning: @extend cannot work across @media boundaries. Use @include for responsive styles.

7.6 Modern Alternatives to @extend

Alternative Technique Advantages Use Case
CSS Custom Properties CSS variables Runtime dynamic, no compilation Theming, dynamic values
Utility Classes Atomic CSS approach Reusable in HTML, no Sass needed Tailwind-style utilities
Mixins with @include Parametric reuse Flexible, predictable Most Sass patterns
Composition Pattern Multiple classes in HTML Explicit, maintainable Component-based design
CSS @layer Cascade layers Better cascade control Modern CSS architecture
PostCSS Plugins Build-time optimization Advanced processing Custom transformations
CSS-in-JS JavaScript styling Component-scoped, dynamic React/Vue components

Example: Modern alternatives in practice

// Alternative 1: CSS Custom Properties (CSS Variables)
:root {
  --button-padding: 10px 20px;
  --button-border: none;
  --button-radius: 4px;
  --button-cursor: pointer;
}

.btn-primary {
  padding: var(--button-padding);
  border: var(--button-border);
  border-radius: var(--button-radius);
  cursor: var(--button-cursor);
  background: var(--primary-color, blue);
}

// Benefits: Runtime dynamic, themeable without recompilation

// Alternative 2: Utility Classes (Tailwind approach)
// Define once, use in HTML
.p-4 { padding: 1rem; }
.rounded { border-radius: 0.25rem; }
.bg-blue-500 { background: #3b82f6; }
.text-white { color: white; }

// HTML: <button class="p-4 rounded bg-blue-500 text-white">

// Alternative 3: Mixins (Recommended for Sass)
@mixin button-base($bg-color, $text-color) {
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  background: $bg-color;
  color: $text-color;
  
  &:hover {
    background: darken($bg-color, 10%);
  }
}

.btn-primary { @include button-base(#007bff, white); }
.btn-success { @include button-base(#28a745, white); }

// Alternative 4: Composition Pattern
.btn { padding: 10px 20px; border: none; cursor: pointer; }
.btn-rounded { border-radius: 4px; }
.btn-primary { background: blue; color: white; }
.btn-large { font-size: 1.2rem; padding: 12px 24px; }

// HTML: <button class="btn btn-rounded btn-primary btn-large">

// Alternative 5: CSS @layer (Modern CSS)
@layer base {
  .button {
    padding: 10px 20px;
    border: none;
  }
}

@layer components {
  .btn-primary {
    @extend .button;  // Or just add class in HTML
    background: blue;
  }
}

// Alternative 6: CSS-in-JS (React example - conceptual)
// const Button = styled.button`
//   padding: 10px 20px;
//   border: none;
//   border-radius: 4px;
//   background: ${props => props.variant === 'primary' ? 'blue' : 'gray'};
// `;

// Comparison: Shared styles across breakpoints
// ❌ @extend doesn't work
%card {
  padding: 1rem;
  background: white;
}

@media (min-width: 768px) {
  .mobile-card {
    @extend %card;  // ERROR!
  }
}

// ✅ CSS Custom Properties work
:root {
  --card-padding: 1rem;
  --card-bg: white;
}

.card {
  padding: var(--card-padding);
  background: var(--card-bg);
}

@media (min-width: 768px) {
  .mobile-card {
    padding: var(--card-padding);
    background: var(--card-bg);
  }
}

// ✅ Mixins work
@mixin card-styles {
  padding: 1rem;
  background: white;
}

.card { @include card-styles; }

@media (min-width: 768px) {
  .mobile-card { @include card-styles; }
}

Extends Summary and Recommendations

  • Use %placeholders for shared static styles (clearfix, text-truncate)
  • Prefer @include over @extend for most use cases
  • @extend cannot cross @media boundaries - use mixins instead
  • Avoid extending complex nested selectors - use simple placeholders
  • Modern CSS: Consider CSS custom properties for theming
  • Composition pattern (multiple classes) often better than inheritance
  • Monitor compiled CSS size when using many extends
  • Document inheritance chains for maintainability
Note: The Sass team recommends using @extend sparingly. Mixins with @include provide better flexibility and are easier to maintain.

8. Modern Sass Module System (@use and @forward)

8.1 @use Directive for Module Import

Feature Syntax Behavior Notes
Basic Import NEW @use 'module'; Loads module with namespace Replaces @import in Dart Sass
Automatic Namespace Last path segment module.scss → module.$var Prevents naming conflicts
Access Members namespace.$variable Dot notation for access Variables, mixins, functions
Load Once Cached after first load Prevents duplicate CSS output Performance optimization
File Extensions Auto-resolves .scss/.sass No extension needed @use 'colors' finds colors.scss
Index Files @use 'folder' Loads folder/_index.scss Module aggregation
Built-in Modules @use 'sass:math' Standard library modules sass:color, sass:list, etc.
Scope File-scoped Not globally available Explicit imports required

Example: Basic @use directive

// _colors.scss
$primary: #007bff;
$secondary: #6c757d;

@mixin theme($color) {
  background: $color;
  color: white;
}

// main.scss
@use 'colors';

.button {
  background: colors.$primary;  // Access with namespace
  
  &:hover {
    background: darken(colors.$primary, 10%);
  }
}

.card {
  @include colors.theme(colors.$secondary);  // Mixin with namespace
}

// Built-in modules
@use 'sass:math';
@use 'sass:color';

.box {
  width: math.div(100%, 3);           // 33.333%
  padding: math.pow(2, 3) + px;        // 8px
  background: color.adjust(#036, $lightness: 20%);
}

// Index file loading
// styles/
//   _index.scss (exports other files)
//   _buttons.scss
//   _cards.scss

@use 'styles';  // Loads styles/_index.scss

.component {
  @include styles.button-base;
}

// Multiple modules
@use 'variables';
@use 'mixins';
@use 'functions';

.element {
  color: variables.$text-color;
  @include mixins.flex-center;
  width: functions.rem(24px);
}
Note: @use is the recommended way to load Sass modules. @import is deprecated and will be removed in future versions.

8.2 @forward Directive for Module Re-export

Feature Syntax Purpose Use Case
Basic Forward @forward 'module'; Re-exports module's members Create public API
Aggregate Modules Multiple @forward statements Combine modules into one Index/barrel files
Show/Hide @forward 'module' show $var; Selective re-export Curated APIs
Hide Members @forward 'module' hide $var; Exclude specific members Keep internals private
Prefix Members @forward 'module' as prefix-*; Add namespace prefix Avoid naming conflicts
Chain Forwarding Forward through multiple files Build module hierarchies Library architecture
CSS Output Includes forwarded CSS Styles bubble up Complete module output

Example: @forward for module organization

// File structure:
// styles/
//   _index.scss      (aggregator)
//   _colors.scss
//   _typography.scss
//   _buttons.scss

// styles/_colors.scss
$primary: #007bff;
$secondary: #6c757d;
$success: #28a745;

// styles/_typography.scss
$font-family: 'Arial', sans-serif;
$line-height: 1.5;

@mixin heading($level) {
  font-size: (4 - $level) * 0.5rem;
  font-weight: 600;
}

// styles/_buttons.scss
@mixin button-base {
  padding: 10px 20px;
  border: none;
  cursor: pointer;
}

// styles/_index.scss (Barrel/Index file)
@forward 'colors';
@forward 'typography';
@forward 'buttons';

// Now users can import everything from one place:
// main.scss
@use 'styles';

.heading {
  color: styles.$primary;           // From colors
  @include styles.heading(1);       // From typography
}

.button {
  @include styles.button-base;      // From buttons
  background: styles.$success;       // From colors
}

// Selective forwarding with 'show'
// _public-api.scss
@forward 'internal' show $public-var, public-mixin;

// Only $public-var and public-mixin are accessible
// Other members from 'internal' remain hidden

// Selective forwarding with 'hide'
// _api.scss
@forward 'colors' hide $internal-color, $debug-color;

// All colors except $internal-color and $debug-color

// Adding prefixes
// _theme.scss
@forward 'light-theme' as light-*;
@forward 'dark-theme' as dark-*;

// Usage:
// @use 'theme';
// background: theme.$light-bg;
// color: theme.$dark-text;

// Combining show and prefix
@forward 'utilities' as util-* show $spacing, calculate-rem;

// Creates: util-$spacing, util-calculate-rem

// Library pattern with forwarding
// lib/
//   _index.scss
//   core/
//     _index.scss
//     _variables.scss
//     _mixins.scss
//   components/
//     _index.scss
//     _buttons.scss
//     _cards.scss

// lib/core/_index.scss
@forward 'variables';
@forward 'mixins';

// lib/components/_index.scss
@forward 'buttons';
@forward 'cards';

// lib/_index.scss
@forward 'core';
@forward 'components';

// User code:
@use 'lib';  // Gets everything through forwarding chain

8.3 Module Namespaces and Aliasing

Technique Syntax Result Use Case
Default Namespace @use 'colors'; colors.$primary Automatic from filename
Custom Alias @use 'colors' as c; c.$primary Shorter names
No Namespace @use 'colors' as *; $primary (global) Direct access (use carefully)
Long Path Names @use 'folder/subfolder/module'; module.$var Last segment becomes namespace
Conflict Resolution Different namespaces No conflicts Multiple modules with same names
Built-in Aliases @use 'sass:math' as m; m.floor() Convenient access

Example: Namespace and aliasing patterns

// Default namespace (filename-based)
@use 'styles/variables';

.component {
  color: variables.$primary;  // Full namespace
}

// Custom alias (shorter)
@use 'styles/variables' as vars;

.component {
  color: vars.$primary;       // Shorter alias
}

// Very short alias
@use 'styles/typography' as t;

.heading {
  @include t.heading(1);
  font-family: t.$font-family;
}

// No namespace (global access)
@use 'colors' as *;

.button {
  background: $primary;       // Direct access, no namespace
  color: $white;
}

// ⚠️ Use 'as *' carefully - can cause naming conflicts!

// Resolving conflicts with aliases
// Both modules have $primary
@use 'brand-colors' as brand;
@use 'ui-colors' as ui;

.header {
  background: brand.$primary;  // Brand primary
}

.button {
  background: ui.$primary;     // UI primary
}

// Long paths - last segment becomes namespace
@use 'styles/theme/dark/variables';

.dark-mode {
  background: variables.$bg;   // 'variables' from last segment
}

// Or use alias for clarity
@use 'styles/theme/dark/variables' as dark-vars;

.dark-mode {
  background: dark-vars.$bg;   // More descriptive
}

// Built-in module aliases
@use 'sass:math' as m;
@use 'sass:color' as c;
@use 'sass:list' as l;
@use 'sass:map' as map;  // Keep original name
@use 'sass:string' as str;

.calculations {
  width: m.div(100%, 3);
  color: c.adjust(#036, $lightness: 20%);
  padding: l.nth((5px, 10px, 15px), 2);
  font-size: str.unquote('"16px"');
}

// Multiple files with same names in different folders
@use 'components/buttons/styles' as button-styles;
@use 'components/cards/styles' as card-styles;

.btn {
  @include button-styles.base;
}

.card {
  @include card-styles.base;
}

// Combining with @forward and aliases
// _public-api.scss
@forward 'internal/colors' as color-*;
@forward 'internal/spacing' as space-*;

// Usage:
@use 'public-api' as api;

.element {
  color: api.$color-primary;
  margin: api.$space-md;
}
Warning: Using @use 'module' as *; removes namespacing and can cause naming conflicts. Use only when necessary.

8.4 Private Members and Module Encapsulation

Feature Syntax Visibility Purpose
Private Variables $-private-var or $_private-var Module-only Internal implementation
Private Mixins @mixin -private() { } Module-only Helper mixins
Private Functions @function -private() { } Module-only Internal calculations
Private Placeholders %-private Module-only Internal extends
Public Members No dash/underscore prefix Exported Public API
@forward Control show/hide directives Selective export Curated public API
Encapsulation Cannot access private from outside Enforced privacy Clean interfaces

Example: Private members and encapsulation

// _theme.scss
// Private members (internal use only)
$-base-size: 16px;
$_internal-ratio: 1.5;

@function -calculate-scale($level) {
  @return $-base-size * $_internal-ratio * $level;
}

@mixin -internal-reset {
  margin: 0;
  padding: 0;
}

%-internal-base {
  box-sizing: border-box;
}

// Public API
$primary-color: #007bff;
$secondary-color: #6c757d;

@function scale($level) {
  @return -calculate-scale($level);  // Uses private function
}

@mixin component-base {
  @include -internal-reset;          // Uses private mixin
  @extend %-internal-base;           // Uses private placeholder
  
  color: $primary-color;
}

// main.scss
@use 'theme';

.component {
  // ✅ Public members accessible
  color: theme.$primary-color;
  font-size: theme.scale(2);
  @include theme.component-base;
  
  // ❌ Private members NOT accessible
  // color: theme.$-base-size;        // ERROR
  // @include theme.-internal-reset;   // ERROR
}

// Library with public API
// _buttons.scss
// Private implementation details
$_default-padding: 10px 20px;
$_default-radius: 4px;

@mixin -set-colors($bg, $text) {
  background: $bg;
  color: $text;
  
  &:hover {
    background: darken($bg, 10%);
  }
}

// Public API
$button-variants: (
  primary: #007bff,
  secondary: #6c757d,
  success: #28a745
);

@mixin button($variant: primary) {
  padding: $_default-padding;
  border-radius: $_default-radius;
  border: none;
  cursor: pointer;
  
  $color: map-get($button-variants, $variant);
  @include -set-colors($color, white);
}

// Usage - only public members accessible
@use 'buttons';

.btn {
  @include buttons.button(primary);  // ✅ Works
  
  // ❌ Cannot access private
  // padding: buttons.$_default-padding;  // ERROR
}

// Selective public API with @forward
// _internal.scss
$-private-config: (debug: true);
$public-colors: (primary: blue);

@mixin -internal-helper { }
@mixin public-mixin { }

// _api.scss
@forward 'internal' show $public-colors, public-mixin;
// Hides $-private-config and -internal-helper

// Advanced: Configuration with private defaults
// _spacing.scss
$-default-base: 8px !default;  // Private default

// Public configuration variable
$base-spacing: $_default-base !default;

@function spacing($multiplier) {
  @return $base-spacing * $multiplier;
}

// Usage:
@use 'spacing' with ($base-spacing: 4px);  // Override public
// Cannot override $-default-base (private)

.element {
  margin: spacing.spacing(2);  // Uses configured base
}

// Module with clear public/private separation
// _grid.scss
// PRIVATE - Implementation details
$_max-columns: 12;
$_gutter: 16px;

@function -column-width($columns) {
  @return percentage($columns / $_max-columns);
}

// PUBLIC - API
@mixin container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 $_gutter;
}

@mixin row {
  display: flex;
  margin: 0 (-$_gutter);
}

@mixin col($size) {
  width: -column-width($size);
  padding: 0 $_gutter;
}

// Clear, documented public interface
// Users don't need to know about private implementation
Note: Private members (starting with - or _) cannot be accessed from other modules, ensuring clean encapsulation.

8.5 Module Configuration with @use...with

Feature Syntax Purpose Notes
Configuration @use 'module' with ($var: value); Override module defaults Module initialization
!default Flag Required in module Makes variable configurable $var: default !default;
Multiple Variables Comma-separated Configure many at once ($a: 1, $b: 2)
One-time Configuration First @use only Subsequent uses inherit Cached configuration
Cannot Reconfigure Once set, cannot change Consistent module state Prevents conflicts
Private Variables Cannot configure private Only public !default vars Encapsulation preserved
Forwarded Configuration Config flows through @forward Nested module config Deep configuration

Example: Module configuration patterns

// _theme.scss - Configurable theme module
// Default values (can be overridden)
$primary-color: #007bff !default;
$secondary-color: #6c757d !default;
$border-radius: 4px !default;
$spacing-unit: 8px !default;

// Derived values (based on configurables)
$primary-dark: darken($primary-color, 10%);
$primary-light: lighten($primary-color, 10%);

@mixin button {
  padding: $spacing-unit * 2;
  border-radius: $border-radius;
  background: $primary-color;
  
  &:hover {
    background: $primary-dark;
  }
}

// main.scss - Configure on import
@use 'theme' with (
  $primary-color: #e91e63,
  $secondary-color: #9c27b0,
  $border-radius: 8px,
  $spacing-unit: 4px
);

.custom-button {
  @include theme.button;  // Uses configured colors
  color: theme.$primary-dark;  // Uses derived value
}

// Multiple modules with different configs
// file1.scss
@use 'theme' with ($primary-color: red);

// file2.scss
@use 'theme' with ($primary-color: blue);  // Different config

// main.scss imports both
@use 'file1';  // Theme configured with red
@use 'file2';  // Theme configured with blue (separate instance)

// Advanced: Responsive grid configuration
// _grid.scss
$columns: 12 !default;
$gutter-width: 16px !default;
$breakpoints: (
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px
) !default;

@function column-width($count) {
  @return percentage($count / $columns);
}

@mixin container($max-width: 1200px) {
  max-width: $max-width;
  margin: 0 auto;
  padding: 0 $gutter-width;
}

// app.scss - Custom grid configuration
@use 'grid' with (
  $columns: 16,
  $gutter-width: 24px,
  $breakpoints: (
    sm: 640px,
    md: 768px,
    lg: 1024px,
    xl: 1280px,
    xxl: 1536px
  )
);

.container {
  @include grid.container(1400px);
}

.col {
  width: grid.column-width(4);  // Uses configured 16-column grid
}

// Design system configuration
// _design-system.scss
$font-family-base: 'Arial', sans-serif !default;
$font-size-base: 16px !default;
$line-height-base: 1.5 !default;

$color-primary: #007bff !default;
$color-secondary: #6c757d !default;
$color-success: #28a745 !default;
$color-danger: #dc3545 !default;

$spacing-scale: (
  xs: 4px,
  sm: 8px,
  md: 16px,
  lg: 24px,
  xl: 32px
) !default;

// Brand A customization
@use 'design-system' with (
  $font-family-base: 'Roboto', sans-serif,
  $color-primary: #ff5722,
  $color-secondary: #795548,
  $spacing-scale: (
    xs: 2px,
    sm: 4px,
    md: 8px,
    lg: 16px,
    xl: 24px
  )
);

// Forwarding with configuration
// _base-theme.scss
$primary: blue !default;

// _extended-theme.scss
@forward 'base-theme';
$secondary: green !default;

// main.scss
@use 'extended-theme' with (
  $primary: red,      // Configures base-theme
  $secondary: purple  // Configures extended-theme
);

// Configuration validation pattern
// _validated-config.scss
$min-font-size: 12px !default;
$max-font-size: 24px !default;

@if $min-font-size >= $max-font-size {
  @error "min-font-size must be less than max-font-size";
}

@if $min-font-size < 10px {
  @warn "Font sizes below 10px may hurt accessibility";
}

// Complex configuration example
// _component-library.scss
$enable-shadows: true !default;
$enable-gradients: false !default;
$enable-transitions: true !default;

$transition-duration: 0.3s !default;
$shadow-size: 0 2px 4px rgba(0,0,0,0.1) !default;

@mixin card {
  padding: 1rem;
  border-radius: 4px;
  
  @if $enable-shadows {
    box-shadow: $shadow-size;
  }
  
  @if $enable-transitions {
    transition: all $transition-duration;
  }
  
  @if $enable-gradients {
    background: linear-gradient(to bottom, #fff, #f5f5f5);
  } @else {
    background: white;
  }
}

// Usage with feature flags
@use 'component-library' with (
  $enable-shadows: false,
  $enable-transitions: true,
  $enable-gradients: true,
  $transition-duration: 0.2s
);
Note: Variables must have !default flag to be configurable via @use...with. This ensures intentional configurability.

8.6 Migration from @import to @use

Aspect @import (Old) @use (New) Migration Step
Global Scope All imports global File-scoped with namespaces Add namespaces to references
Multiple Imports CSS duplicated each time Loaded once, cached Remove duplicate imports
Naming Conflicts Last import wins Namespaces prevent conflicts Resolve with aliases
Load Order Critical, fragile Dependency-based Review dependencies
Private Members No privacy - or _ prefix for private Mark internal members
Built-in Functions Global (floor, lighten) Module-based (math.floor) Add module prefix
Deprecation Will be removed Recommended approach Migrate before removal

Example: Migration guide and patterns

// BEFORE: Old @import style
// _variables.scss
$primary-color: #007bff;
$font-size: 16px;

// _mixins.scss
@mixin button {
  padding: 10px 20px;
}

// main.scss
@import 'variables';
@import 'mixins';
@import 'variables';  // ❌ Duplicated CSS

.button {
  color: $primary-color;      // Global access
  font-size: $font-size;      // Global access
  @include button;            // Global access
}

// AFTER: New @use style
// _variables.scss (same)
$primary-color: #007bff;
$font-size: 16px;

// _mixins.scss
// If needs variables, must import
@use 'variables';

@mixin button {
  padding: 10px 20px;
  color: variables.$primary-color;  // Namespaced
}

// main.scss
@use 'variables';
@use 'mixins';

.button {
  color: variables.$primary-color;   // Namespaced
  font-size: variables.$font-size;   // Namespaced
  @include mixins.button;            // Namespaced
}

// Migration Strategy 1: Gradual with 'as *'
// Phase 1: Switch to @use with global namespace
@use 'variables' as *;
@use 'mixins' as *;

.button {
  color: $primary-color;      // Still works (no namespace)
  @include button;            // Still works
}

// Phase 2: Add namespaces gradually
@use 'variables' as vars;
@use 'mixins' as mix;

.button {
  color: vars.$primary-color;
  @include mix.button;
}

// Migration Strategy 2: Built-in modules
// BEFORE
$width: floor(10.7px);
$color: lighten(#333, 20%);

// AFTER
@use 'sass:math';
@use 'sass:color';

$width: math.floor(10.7px);
$color: color.adjust(#333, $lightness: 20%);

// Common migration patterns
// Pattern 1: Global utilities to module
// BEFORE: _utilities.scss
@mixin clearfix { }
@mixin truncate { }
%flex-center { }

// AFTER: Keep same, just use differently
// _utilities.scss (no changes needed)
@mixin clearfix { }
@mixin truncate { }
%flex-center { }

// Usage changes:
// BEFORE
@import 'utilities';
@include clearfix;

// AFTER
@use 'utilities' as util;
@include util.clearfix;

// Pattern 2: Handling @import in modules
// BEFORE: _buttons.scss
@import 'variables';  // Gets variables globally

@mixin button {
  color: $primary;
}

// AFTER: _buttons.scss
@use 'variables';  // Explicit dependency

@mixin button {
  color: variables.$primary;  // Namespaced
}

// Pattern 3: Index files (barrel exports)
// BEFORE: styles/_index.scss
@import 'variables';
@import 'mixins';
@import 'functions';

// AFTER: styles/_index.scss
@forward 'variables';
@forward 'mixins';
@forward 'functions';

// Usage:
@use 'styles';  // Gets everything

// Pattern 4: Configurable libraries
// BEFORE: Global configuration
$theme-primary: red;
@import 'theme';

// AFTER: Module configuration
@use 'theme' with ($primary: red);

// Pattern 5: Dealing with third-party @import
// If library still uses @import, you can still @use it
// _third-party-lib.scss (uses @import internally)
@import 'some-old-file';

// your-file.scss
@use 'third-party-lib';  // Works, but shows deprecation warnings

// Pattern 6: Mixed migration (transitional)
// Use @import and @use together during migration
@import 'old-global-utils';     // Still using @import
@use 'new-module' as new;       // Migrated to @use

.component {
  @include old-mixin;           // From @import
  @include new.new-mixin;       // From @use
}

// Complete migration checklist:
// ☐ Replace @import with @use
// ☐ Add namespaces to all references
// ☐ Update built-in function calls
// ☐ Mark private members with - or _
// ☐ Use @forward for index files
// ☐ Add !default to configurable variables
// ☐ Remove duplicate imports
// ☐ Test thoroughly
// ☐ Update documentation

Module System Best Practices

  • Always use @use instead of @import for new code
  • Use @forward in index files to create public APIs
  • Prefix private members with - or _ for encapsulation
  • Use @use...with for module configuration
  • Prefer descriptive namespaces or aliases over as *
  • Mark configurable variables with !default flag
  • Use built-in modules with @use 'sass:math' etc.
  • Plan migration from @import incrementally for large codebases
Warning: @import is deprecated and will be removed in Dart Sass 2.0. Migrate to @use and @forward as soon as possible.

9. Built-in Modules and Standard Library

9.1 sass:color Module Functions

Function Syntax Description Example
adjust() color.adjust($color, $args...) Adjusts color properties by amount adjust(#6b717f, $red: 15)
change() color.change($color, $args...) Sets color properties to value change(#6b717f, $lightness: 50%)
scale() color.scale($color, $args...) Scales properties by percentage scale(#6b717f, $lightness: 30%)
mix() color.mix($c1, $c2, $weight) Blends two colors mix(#036, #d2e1dd, 75%)
invert() color.invert($color, $weight) Inverts color (optional partial) invert(#6b717f, 80%)
complement() color.complement($color) Returns complementary color complement(#6b717f)
grayscale() color.grayscale($color) Removes all saturation grayscale(#6b717f)
ie-hex-str() color.ie-hex-str($color) IE-compatible hex with alpha ie-hex-str(rgba(0,0,0,0.5))
alpha()/opacity() color.alpha($color) Returns alpha channel (0-1) alpha(rgba(0,0,0,0.8)) → 0.8
red()/green()/blue() color.red($color) Returns RGB channel (0-255) red(#6b717f) → 107
hue() color.hue($color) Returns hue (0-360deg) hue(#6b717f)
saturation() color.saturation($color) Returns saturation (0-100%) saturation(#6b717f)
lightness() color.lightness($color) Returns lightness (0-100%) lightness(#6b717f)
whiteness()/blackness() color.whiteness($color) Returns HWB components HWB color model values

Example: sass:color module usage

@use 'sass:color';

$base-color: #6b717f;

// adjust() - Increase/decrease by amount
.adjust-demo {
  // Adjust individual channels
  color: color.adjust($base-color, $red: 15);
  background: color.adjust($base-color, $lightness: 10%);
  border-color: color.adjust($base-color, $alpha: -0.4);
  
  // Multiple adjustments
  outline-color: color.adjust($base-color, 
    $red: 10, 
    $blue: -20, 
    $lightness: 5%
  );
}

// change() - Set to specific value
.change-demo {
  color: color.change($base-color, $lightness: 50%);
  background: color.change($base-color, $alpha: 0.5);
  border-color: color.change($base-color, $hue: 180deg);
}

// scale() - Scale by percentage of available range
.scale-demo {
  // Scale lightness 30% toward white
  color: color.scale($base-color, $lightness: 30%);
  
  // Scale saturation 50% toward grayscale
  background: color.scale($base-color, $saturation: -50%);
  
  // Multiple scales
  border-color: color.scale($base-color, 
    $lightness: 40%, 
    $saturation: 20%
  );
}

// Comparison: lighten vs adjust vs scale
$color: #6b717f;
.comparison {
  // Old way (deprecated)
  // color: lighten($color, 20%);
  
  // adjust - adds 20% lightness
  color: color.adjust($color, $lightness: 20%);
  
  // scale - scales 20% toward white (more natural)
  background: color.scale($color, $lightness: 20%);
}

// Color mixing
.mix-demo {
  // 75% of first color, 25% of second
  color: color.mix(#036, #d2e1dd, 75%);
  
  // 50-50 mix (default)
  background: color.mix(red, blue);
  
  // Create tints and shades
  $tint: color.mix(white, $base-color, 20%);
  $shade: color.mix(black, $base-color, 20%);
}

// Color information extraction
.info-demo {
  // Get channels
  $r: color.red($base-color);      // 107
  $g: color.green($base-color);    // 113
  $b: color.blue($base-color);     // 127
  
  // HSL values
  $h: color.hue($base-color);           // 225deg
  $s: color.saturation($base-color);    // 8.547%
  $l: color.lightness($base-color);     // 45.882%
  
  // Alpha
  $a: color.alpha(rgba(0,0,0,0.5));     // 0.5
}

// Practical: Theme generation
$primary: #007bff;

$theme: (
  primary: $primary,
  primary-light: color.scale($primary, $lightness: 40%),
  primary-dark: color.scale($primary, $lightness: -40%),
  primary-pale: color.mix(white, $primary, 80%),
  primary-muted: color.scale($primary, $saturation: -60%),
  complement: color.complement($primary)
);

// Practical: Contrast-based text color
@function text-color($bg) {
  @if color.lightness($bg) > 50% {
    @return #000;
  } @else {
    @return #fff;
  }
}

.button {
  $bg: #3498db;
  background: $bg;
  color: text-color($bg);  // Returns #fff
}

9.2 sass:list Module Operations

Function Syntax Description Example
append() list.append($list, $val, $sep) Adds value to end append((a, b), c) → a, b, c
index() list.index($list, $value) Returns position or null index((a, b, c), b) → 2
is-bracketed() list.is-bracketed($list) Checks for square brackets is-bracketed([a, b]) → true
join() list.join($l1, $l2, $sep) Combines two lists join((a, b), (c, d))
length() list.length($list) Returns item count length((a, b, c)) → 3
nth() list.nth($list, $n) Gets value at position nth((a, b, c), 2) → b
separator() list.separator($list) Returns separator type comma, space, slash, null
set-nth() list.set-nth($list, $n, $val) Replaces value at position set-nth((a, b), 1, z) → z, b
slash() list.slash($elements...) Creates slash-separated list slash(1em, 1.5em, 2em)
zip() list.zip($lists...) Combines lists into sub-lists zip((a, b), (1, 2)) → (a 1), (b 2)

Example: sass:list module operations

@use 'sass:list';

// Basic list operations
$colors: red, green, blue;

.list-demo {
  // Length
  $count: list.length($colors);  // 3
  
  // Access by index (1-based)
  $first: list.nth($colors, 1);  // red
  $last: list.nth($colors, -1);  // blue
  
  // Find index
  $pos: list.index($colors, green);  // 2
  
  // Append
  $extended: list.append($colors, yellow);  // red, green, blue, yellow
  
  // Set value at position
  $modified: list.set-nth($colors, 2, orange);  // red, orange, blue
}

// Joining lists
.join-demo {
  $list1: (a, b);
  $list2: (c, d);
  
  // Join with comma (default)
  $joined: list.join($list1, $list2);  // a, b, c, d
  
  // Join with space
  $spaced: list.join($list1, $list2, space);  // a b c d
  
  // Join with slash
  $slashed: list.join($list1, $list2, slash);  // a / b / c / d
}

// Slash-separated lists (for font shorthand)
.slash-demo {
  // CSS font shorthand: size / line-height
  font: 16px list.slash(1.2em) Arial;
  
  // Creates: 16px / 1.2em Arial
}

// Zip lists together
.zip-demo {
  $names: (name1, name2, name3);
  $values: (10px, 20px, 30px);
  
  $pairs: list.zip($names, $values);
  // Result: (name1 10px), (name2 20px), (name3 30px)
  
  @each $pair in $pairs {
    $name: list.nth($pair, 1);
    $value: list.nth($pair, 2);
    
    .#{$name} {
      padding: $value;
    }
  }
}

// Practical: Utility list functions
@function contains($list, $value) {
  @return list.index($list, $value) != null;
}

@function first($list) {
  @return list.nth($list, 1);
}

@function last($list) {
  @return list.nth($list, -1);
}

@function rest($list) {
  $result: ();
  @for $i from 2 through list.length($list) {
    $result: list.append($result, list.nth($list, $i));
  }
  @return $result;
}

// Usage
$items: (a, b, c, d);
.utils {
  $has-b: contains($items, b);      // true
  $head: first($items);              // a
  $tail: last($items);               // d
  $remaining: rest($items);          // b, c, d
}

// Bracket detection
.brackets {
  $regular: (a, b, c);
  $bracketed: [a, b, c];
  
  $is-bracket: list.is-bracketed($bracketed);  // true
  $not-bracket: list.is-bracketed($regular);   // false
}

// Separator detection
.separators {
  $comma-list: (a, b, c);
  $space-list: a b c;
  $single: (a,);
  
  $sep1: list.separator($comma-list);  // comma
  $sep2: list.separator($space-list);  // space
  $sep3: list.separator($single);      // comma
}

9.3 sass:map Module Utilities

Function Syntax Description Example
get() map.get($map, $key) Returns value or null get((a: 1), a) → 1
has-key() map.has-key($map, $key) Checks if key exists has-key((a: 1), a) → true
keys() map.keys($map) Returns list of keys keys((a: 1, b: 2)) → a, b
values() map.values($map) Returns list of values values((a: 1, b: 2)) → 1, 2
merge() map.merge($map1, $map2) Combines maps (shallow) Second map overwrites first
deep-merge() map.deep-merge($map1, $map2) Recursively merges nested Merges nested maps too
remove() map.remove($map, $keys...) Returns map without keys remove((a: 1, b: 2), a)
set() map.set($map, $key, $val) Adds/updates key-value set((a: 1), b, 2)
deep-remove() map.deep-remove($map, $keys...) Removes nested key path Deep key removal

Example: sass:map module utilities

@use 'sass:map';

$theme: (
  primary: #007bff,
  secondary: #6c757d,
  success: #28a745
);

// Basic map operations
.map-demo {
  // Get value
  $color: map.get($theme, primary);  // #007bff
  
  // Check key existence
  $has: map.has-key($theme, danger);  // false
  
  // Get all keys
  $all-keys: map.keys($theme);  // primary, secondary, success
  
  // Get all values
  $all-vals: map.values($theme);  // #007bff, #6c757d, #28a745
}

// Merging maps
.merge-demo {
  $defaults: (size: 16px, weight: 400);
  $custom: (size: 18px, family: Arial);
  
  // Shallow merge (custom overwrites)
  $config: map.merge($defaults, $custom);
  // Result: (size: 18px, weight: 400, family: Arial)
}

// Deep merge for nested maps
.deep-merge-demo {
  $theme1: (
    colors: (
      primary: blue,
      secondary: gray
    ),
    spacing: (
      sm: 8px
    )
  );
  
  $theme2: (
    colors: (
      primary: red,  // Overwrites
      accent: green   // Adds
    ),
    spacing: (
      md: 16px        // Adds
    )
  );
  
  $merged: map.deep-merge($theme1, $theme2);
  // Result: (
  //   colors: (primary: red, secondary: gray, accent: green),
  //   spacing: (sm: 8px, md: 16px)
  // )
}

// Adding/updating values
.set-demo {
  $colors: (red: #f00, green: #0f0);
  
  // Add new key
  $updated: map.set($colors, blue, #00f);
  // (red: #f00, green: #0f0, blue: #00f)
  
  // Update existing
  $modified: map.set($colors, red, #ff0000);
  // (red: #ff0000, green: #0f0)
  
  // Set multiple (chain calls)
  $multi: map.set($colors, blue, #00f);
  $multi: map.set($multi, yellow, #ff0);
}

// Removing keys
.remove-demo {
  $config: (a: 1, b: 2, c: 3, d: 4);
  
  // Remove single key
  $removed: map.remove($config, b);
  // (a: 1, c: 3, d: 4)
  
  // Remove multiple keys
  $cleaned: map.remove($config, a, c);
  // (b: 2, d: 4)
}

// Practical: Safe map access with default
@function map-get-default($map, $key, $default) {
  @if map.has-key($map, $key) {
    @return map.get($map, $key);
  }
  @return $default;
}

$settings: (timeout: 5000);
.safe-access {
  $timeout: map-get-default($settings, timeout, 3000);    // 5000
  $retries: map-get-default($settings, retries, 3);       // 3 (default)
}

// Practical: Map iteration helpers
@function map-to-list($map) {
  $list: ();
  @each $key, $value in $map {
    $list: list.append($list, ($key, $value));
  }
  @return $list;
}

@function filter-map($map, $keys) {
  $result: ();
  @each $key in $keys {
    @if map.has-key($map, $key) {
      $result: map.set($result, $key, map.get($map, $key));
    }
  }
  @return $result;
}

// Advanced: Nested map access
@function deep-get($map, $keys...) {
  @each $key in $keys {
    $map: map.get($map, $key);
    @if $map == null {
      @return null;
    }
  }
  @return $map;
}

$theme-config: (
  colors: (
    primary: (
      base: #007bff,
      light: #3395ff,
      dark: #0056b3
    )
  )
);

.deep-access {
  $base-color: deep-get($theme-config, colors, primary, base);
  // Returns: #007bff
}

9.4 sass:math Module Calculations

Function Syntax Description Example
abs() math.abs($number) Absolute value abs(-15) → 15
ceil() math.ceil($number) Round up ceil(4.2) → 5
floor() math.floor($number) Round down floor(4.8) → 4
round() math.round($number) Round to nearest round(4.5) → 5
max() math.max($numbers...) Largest value max(1, 5, 3) → 5
min() math.min($numbers...) Smallest value min(1, 5, 3) → 1
clamp() math.clamp($min, $val, $max) Constrain between min/max clamp(0, 150, 100) → 100
div() math.div($num1, $num2) Division (replaces /) div(100px, 2) → 50px
percentage() math.percentage($number) Convert to percentage percentage(0.5) → 50%
pow() math.pow($base, $exponent) Exponentiation pow(2, 3) → 8
sqrt() math.sqrt($number) Square root sqrt(16) → 4
cos()/sin()/tan() math.cos($angle) Trigonometric functions cos(0deg) → 1
acos()/asin()/atan()/atan2() math.acos($number) Inverse trig functions Returns angle
log() math.log($number, $base) Logarithm log(100, 10) → 2
unit() math.unit($number) Returns unit string unit(10px) → "px"
is-unitless() math.is-unitless($number) Checks if no unit is-unitless(10) → true
compatible() math.compatible($n1, $n2) Can units be added? compatible(1px, 1em) → false

Example: sass:math module calculations

@use 'sass:math';

// Basic arithmetic
.math-demo {
  // Division (NEW way in Dart Sass)
  width: math.div(100%, 3);          // 33.333%
  padding: math.div(24px, 2);        // 12px
  
  // Rounding
  $value: 4.7;
  font-size: math.ceil($value);      // 5
  line-height: math.floor($value);   // 4
  margin: math.round($value);        // 5
  
  // Min/Max
  width: math.max(300px, 50%, 20vw);
  padding: math.min(2rem, 5%);
  
  // Clamp (constrain value)
  font-size: math.clamp(14px, 2vw, 24px);
}

// Advanced math
.advanced {
  // Exponents
  $size: math.pow(2, 4);             // 16
  
  // Square root
  $diagonal: math.sqrt(2) * 100px;   // ~141.42px
  
  // Absolute value
  margin: math.abs(-20px);           // 20px
  
  // Percentage conversion
  width: math.percentage(math.div(3, 4));  // 75%
}

// Trigonometry (angles)
.trig-demo {
  // Trigonometric functions
  $angle: 45deg;
  
  $cos-val: math.cos($angle);        // 0.707...
  $sin-val: math.sin($angle);        // 0.707...
  $tan-val: math.tan($angle);        // 1
  
  // Inverse trig
  $acos-val: math.acos(0.5);         // 60deg
  $asin-val: math.asin(1);           // 90deg
  $atan-val: math.atan(1);           // 45deg
}

// Logarithms
.log-demo {
  // Natural log (base e)
  $ln: math.log(math.$e);            // 1
  
  // Log base 10
  $log10: math.log(100, 10);         // 2
  
  // Log base 2
  $log2: math.log(8, 2);             // 3
}

// Mathematical constants
.constants {
  // Euler's number
  $e: math.$e;                       // 2.718281828459045
  
  // Pi
  $pi: math.$pi;                     // 3.141592653589793
  
  // Usage
  $circle-area: math.$pi * math.pow(5px, 2);
}

// Unit operations
.units {
  $px-value: 16px;
  $unitless: 10;
  
  // Check if unitless
  $is-plain: math.is-unitless($unitless);      // true
  $has-unit: math.is-unitless($px-value);      // false
  
  // Get unit
  $unit-str: math.unit($px-value);             // "px"
  
  // Check compatibility
  $can-add: math.compatible(1px, 1em);         // false
  $can-add2: math.compatible(1px, 2px);        // true
}

// Practical: Fluid typography
@function fluid-size($min, $max, $min-vw: 320px, $max-vw: 1200px) {
  $slope: math.div($max - $min, $max-vw - $min-vw);
  $y-intercept: $min - $slope * $min-vw;
  
  @return calc(#{$y-intercept} + #{$slope * 100}vw);
}

.heading {
  font-size: fluid-size(16px, 32px);
}

// Practical: Aspect ratio padding
@function aspect-ratio($width, $height) {
  @return math.percentage(math.div($height, $width));
}

.video-16-9 {
  padding-bottom: aspect-ratio(16, 9);  // 56.25%
}

// Practical: Grid column width
@function grid-column-width($columns, $total: 12, $gutter: 30px) {
  $column-width: math.div(100% - ($total - 1) * $gutter, $total);
  $width: $column-width * $columns + ($columns - 1) * $gutter;
  
  @return math.floor($width * 100) * 0.01%;
}

.col-4 {
  width: grid-column-width(4);
}

// Practical: Modular scale
@function modular-scale($level, $base: 16px, $ratio: 1.618) {
  @return $base * math.pow($ratio, $level);
}

h1 { font-size: modular-scale(4); }   // 68.773px
h2 { font-size: modular-scale(3); }   // 42.517px
h3 { font-size: modular-scale(2); }   // 26.287px
Note: Use math.div() instead of / for division in Dart Sass. The / operator is deprecated for division.

9.5 sass:meta Module Reflection Functions

Function Syntax Description Use Case
type-of() meta.type-of($value) Returns type as string Type checking, validation
inspect() meta.inspect($value) String representation Debugging, logging
variable-exists() meta.variable-exists($name) Check if var defined Conditional logic
global-variable-exists() meta.global-variable-exists($name) Check global var Scope validation
function-exists() meta.function-exists($name) Check if function defined Feature detection
mixin-exists() meta.mixin-exists($name) Check if mixin defined Conditional includes
get-function() meta.get-function($name) Returns function reference Dynamic function calls
call() meta.call($function, $args...) Invoke function dynamically Callback patterns
content-exists() meta.content-exists() Check if @content passed Conditional @content
keywords() meta.keywords($args) Extract keyword arguments Argument handling
module-functions() meta.module-functions($module) List module's functions Introspection
module-variables() meta.module-variables($module) List module's variables Introspection

Example: sass:meta reflection and introspection

@use 'sass:meta';
@use 'sass:map';

// Type checking
.type-demo {
  $value: 10px;
  $type: meta.type-of($value);       // "number"
  
  // All types: number, string, color, list, map,
  //            bool, null, function, arglist
  
  @if meta.type-of($value) == 'number' {
    width: $value;
  }
}

// Inspect for debugging
@debug meta.inspect((a: 1, b: 2));   // "(a: 1, b: 2)"
@debug meta.inspect(#f00);           // "red"

// Variable existence checking
$global-color: red;

@mixin conditional-color {
  @if meta.variable-exists(local-color) {
    color: $local-color;
  } @else if meta.global-variable-exists(global-color) {
    color: $global-color;
  } @else {
    color: black;
  }
}

// Function/mixin existence
@mixin apply-if-exists($mixin-name) {
  @if meta.mixin-exists($mixin-name) {
    @include meta.get-mixin($mixin-name);
  } @else {
    @warn "Mixin #{$mixin-name} does not exist";
  }
}

// Dynamic function calls
@function add($a, $b) {
  @return $a + $b;
}

@function multiply($a, $b) {
  @return $a * $b;
}

.dynamic-call {
  // Get function reference
  $fn: meta.get-function('add');
  
  // Call it dynamically
  $result: meta.call($fn, 10, 5);    // 15
  
  // Or in one step
  $result2: meta.call(meta.get-function('multiply'), 3, 4);  // 12
}

// Practical: Function dispatcher
@function calculate($operation, $a, $b) {
  @if meta.function-exists($operation) {
    $fn: meta.get-function($operation);
    @return meta.call($fn, $a, $b);
  }
  @error "Unknown operation: #{$operation}";
}

.calculator {
  width: calculate('add', 100px, 50px);        // 150px
  height: calculate('multiply', 10px, 3);      // 30px
}

// Content existence checking
@mixin wrapper {
  .wrapper {
    padding: 1rem;
    
    @if meta.content-exists() {
      @content;
    } @else {
      // Default content
      background: gray;
    }
  }
}

@include wrapper {
  background: blue;  // Custom content
}

@include wrapper;  // Uses default

// Keywords extraction
@mixin button($args...) {
  $config: meta.keywords($args);
  
  background: map.get($config, bg) or blue;
  color: map.get($config, color) or white;
  padding: map.get($config, padding) or 10px;
}

.btn {
  @include button($bg: red, $padding: 15px);
}

// Module introspection
@use 'sass:math';

.introspection {
  // List all functions in math module
  $math-functions: meta.module-functions('math');
  // Returns map: (abs: function, ceil: function, ...)
  
  // List all variables (if any)
  $math-vars: meta.module-variables('math');
  // Returns map with $e, $pi, etc.
}

// Advanced: Type-safe function
@function safe-divide($a, $b) {
  @if meta.type-of($a) != 'number' {
    @error "$a must be a number, got #{meta.type-of($a)}";
  }
  
  @if meta.type-of($b) != 'number' {
    @error "$b must be a number, got #{meta.type-of($b)}";
  }
  
  @if $b == 0 {
    @error "Division by zero";
  }
  
  @return $a / $b;
}

// Practical: Plugin system
$_plugins: ();

@mixin register-plugin($name, $function) {
  $_plugins: map.merge($_plugins, ($name: $function)) !global;
}

@function run-plugin($name, $args...) {
  @if map.has-key($_plugins, $name) {
    $fn: map.get($_plugins, $name);
    @return meta.call($fn, $args...);
  }
  @error "Plugin #{$name} not found";
}

9.6 sass:selector Module Manipulation

Function Syntax Description Use Case
append() selector.append($selectors...) Combines selectors Compound selectors
extend() selector.extend($sel, $ex, $exd) Extends selectors Programmatic @extend
nest() selector.nest($selectors...) Nests selectors Dynamic nesting
parse() selector.parse($selector) Converts string to selector String to selector list
replace() selector.replace($sel, $old, $new) Replaces selector part Selector transformation
unify() selector.unify($sel1, $sel2) Combines if possible Selector intersection
is-superselector() selector.is-superselector($s, $c) Checks if s contains c Specificity checking
simple-selectors() selector.simple-selectors($sel) Breaks into components Selector analysis

Example: sass:selector manipulation

@use 'sass:selector';

// Parse selector from string
.parse-demo {
  $parsed: selector.parse('.foo .bar, .baz');
  // Returns: ((.foo .bar), (.baz))
}

// Nest selectors programmatically
.nest-demo {
  $parent: '.parent';
  $child: '.child';
  
  $nested: selector.nest($parent, $child);
  // Returns: .parent .child
  
  $complex: selector.nest('.outer', '.inner', '.deep');
  // Returns: .outer .inner .deep
}

// Append selectors (no space)
.append-demo {
  $base: '.button';
  $modifier: '.--primary';
  
  $combined: selector.append($base, $modifier);
  // Returns: .button.--primary
  
  // Multiple appends
  $multi: selector.append('.btn', '.is-active', ':hover');
  // Returns: .btn.is-active:hover
}

// Replace selector parts
.replace-demo {
  $selector: '.old-class .nested';
  
  $updated: selector.replace($selector, '.old-class', '.new-class');
  // Returns: .new-class .nested
}

// Unify selectors (intersection)
.unify-demo {
  $unified: selector.unify('.button', '.primary');
  // Returns: .button.primary
  
  $tags: selector.unify('div', '.class');
  // Returns: div.class
  
  // Incompatible returns null
  $incomp: selector.unify('div', 'span');
  // Returns: null (can't be both)
}

// Check superselector
.superselector-demo {
  $is-super: selector.is-superselector('.a .b', '.b');
  // true - '.a .b' matches all '.b' would match
  
  $not-super: selector.is-superselector('.b', '.a .b');
  // false
}

// Simple selectors breakdown
.simple-demo {
  $simple: selector.simple-selectors('.btn.is-active[disabled]');
  // Returns: ('.btn', '.is-active', '[disabled]')
}

// Practical: BEM modifier generator
@function bem-modifier($block, $modifiers...) {
  $selectors: ();
  
  @each $modifier in $modifiers {
    $sel: selector.append($block, '--#{$modifier}');
    $selectors: list.append($selectors, $sel, comma);
  }
  
  @return $selectors;
}

#{bem-modifier('.button', 'primary', 'large', 'disabled')} {
  // Generates: .button--primary, .button--large, .button--disabled
  display: inline-block;
}

// Practical: Dynamic theming
@mixin theme-variants($selector, $themes) {
  @each $theme, $color in $themes {
    $themed-selector: selector.nest('.theme-#{$theme}', $selector);
    
    #{$themed-selector} {
      background: $color;
    }
  }
}

@include theme-variants('.card', (light: #fff, dark: #333, blue: #007bff));
// Generates:
// .theme-light .card { background: #fff; }
// .theme-dark .card { background: #333; }
// .theme-blue .card { background: #007bff; }

9.7 sass:string Module Processing

Function Syntax Description Example
quote() string.quote($string) Adds quotes quote(Arial) → "Arial"
unquote() string.unquote($string) Removes quotes unquote("Arial") → Arial
length() string.length($string) Character count length("hello") → 5
index() string.index($str, $substr) Position of substring index("hello", "ll") → 3
insert() string.insert($str, $ins, $idx) Inserts at position insert("abc", "X", 2) → "aXbc"
slice() string.slice($str, $start, $end) Extracts substring slice("hello", 2, 4) → "ell"
to-upper-case() string.to-upper-case($str) Converts to uppercase to-upper-case("hi") → "HI"
to-lower-case() string.to-lower-case($str) Converts to lowercase to-lower-case("HI") → "hi"
unique-id() string.unique-id() Generates unique string unique-id() → "u4b2c3d4"

Example: sass:string processing

@use 'sass:string';

// Basic string operations
.string-demo {
  $text: "Hello World";
  
  // Length
  $len: string.length($text);           // 11
  
  // Find substring
  $pos: string.index($text, "World");   // 7
  
  // Extract
  $sub: string.slice($text, 1, 5);      // "Hello"
  $last: string.slice($text, -5, -1);   // "World"
  
  // Insert
  $inserted: string.insert($text, " Beautiful", 6);
  // "Hello Beautiful World"
  
  // Case conversion
  $upper: string.to-upper-case($text);  // "HELLO WORLD"
  $lower: string.to-lower-case($text);  // "hello world"
}

// Quote handling
.quote-demo {
  $unquoted: Arial;
  $quoted: "Helvetica";
  
  $add-quotes: string.quote($unquoted);      // "Arial"
  $remove-quotes: string.unquote($quoted);   // Helvetica
  
  // Font family with spaces
  $font: Open Sans;
  font-family: string.quote($font);          // "Open Sans"
}

// Unique IDs
.unique-demo {
  $id1: string.unique-id();  // "u1a2b3c4"
  $id2: string.unique-id();  // "u5d6e7f8" (different)
  
  // Use for animation names
  $anim-name: 'slide-' + string.unique-id();
  animation-name: string.unquote($anim-name);
}

// Practical: String replacement
@function str-replace($string, $search, $replace: '') {
  $index: string.index($string, $search);
  
  @if $index {
    $before: string.slice($string, 1, $index - 1);
    $after: string.slice($string, $index + string.length($search));
    @return $before + $replace + str-replace($after, $search, $replace);
  }
  
  @return $string;
}

.replace-demo {
  $path: "assets/images/icon.png";
  $new-path: str-replace($path, "assets", "public");
  // Result: "public/images/icon.png"
}

// Practical: String contains
@function str-contains($string, $substring) {
  @return string.index($string, $substring) != null;
}

.contains-demo {
  $url: "https://example.com";
  $is-https: str-contains($url, "https");  // true
}

// Practical: Camel case to kebab case
@function to-kebab-case($string) {
  $result: '';
  
  @for $i from 1 through string.length($string) {
    $char: string.slice($string, $i, $i);
    $lower: string.to-lower-case($char);
    
    @if $char != $lower and $i > 1 {
      $result: $result + '-' + $lower;
    } @else {
      $result: $result + $lower;
    }
  }
  
  @return $result;
}

.kebab {
  // backgroundColor → background-color
  $kebab: to-kebab-case("backgroundColor");
}

// Practical: Truncate with ellipsis
@function truncate-string($string, $max-length) {
  @if string.length($string) > $max-length {
    @return string.slice($string, 1, $max-length - 3) + '...';
  }
  @return $string;
}

.truncate {
  content: string.unquote('"' + truncate-string("Very long text here", 10) + '"');
  // "Very lo..."
}

Built-in Modules Summary

  • sass:color - Comprehensive color manipulation (adjust, scale, mix)
  • sass:list - List operations (append, join, zip, nth)
  • sass:map - Map utilities (get, set, merge, deep-merge)
  • sass:math - Mathematical calculations (div, pow, trig, constants)
  • sass:meta - Reflection and introspection (type-of, call, inspect)
  • sass:selector - Selector manipulation (nest, append, parse)
  • sass:string - String processing (slice, index, case conversion)
  • All modules require @use 'sass:module-name'; in modern Sass
Note: Built-in modules are namespaced in Dart Sass. Always use @use 'sass:module' instead of global functions.

10. Operators and Expression Evaluation

10.1 Arithmetic Operators (+, -, *, /, %)

Operator Description Example Result
+ Addition 10px + 5px 15px
- Subtraction 20px - 8px 12px
* Multiplication 5px * 3 15px
/ Division (deprecated) math.div(20px, 4) 5px
% Modulo (remainder) 17px % 5px 2px
+ Unary plus +5px 5px
- Unary minus (negation) -10px -10px

Example: Arithmetic operations

@use 'sass:math';

// Basic arithmetic
.arithmetic {
  // Addition
  width: 100px + 50px;              // 150px
  margin: 1rem + 2rem;              // 3rem
  
  // Subtraction
  height: 500px - 100px;            // 400px
  padding: 3em - 1em;               // 2em
  
  // Multiplication (one must be unitless)
  font-size: 16px * 1.5;            // 24px
  line-height: 1.2 * 2;             // 2.4
  
  // Division - MUST use math.div() in Dart Sass
  width: math.div(100%, 3);         // 33.333%
  height: math.div(200px, 2);       // 100px
  
  // Modulo
  $remainder: 17px % 5px;           // 2px
  $mod: 23 % 7;                     // 2
}

// Unit handling
.units {
  // Compatible units can be added
  width: 100px + 2em;               // ERROR: Incompatible units
  
  // Same units
  width: 100px + 50px;              // 150px
  
  // Multiplication requires one unitless
  width: 10px * 2;                  // 20px (correct)
  width: 10px * 2px;                // ERROR: Can't multiply px * px
  
  // Division
  width: math.div(100px, 2);        // 50px
  width: math.div(100px, 2px);      // 50 (unitless)
}

// Operator precedence
.precedence {
  // Multiplication before addition
  width: 10px + 5px * 2;            // 20px (not 30px)
  
  // Use parentheses for clarity
  width: (10px + 5px) * 2;          // 30px
  
  // Division first
  margin: 100px - math.div(50px, 2);  // 75px
}

// Negative numbers
.negatives {
  // Unary minus
  margin: -10px;
  top: -(20px + 5px);               // -25px
  
  // Subtraction vs negative
  width: 100px - 20px;              // 80px (subtraction)
  width: 100px -20px;               // 100px -20px (list!)
  width: 100px (-20px);             // 80px (subtraction with parens)
}

// Practical: Grid column calculation
@function grid-width($columns, $total: 12, $gutter: 30px) {
  $column-width: math.div(100% - ($total - 1) * $gutter, $total);
  @return $column-width * $columns + ($columns - 1) * $gutter;
}

.col-4 {
  width: grid-width(4);
}

// Practical: Fluid spacing
@function fluid-space($min, $max, $min-vw: 320px, $max-vw: 1200px) {
  $slope: math.div($max - $min, $max-vw - $min-vw);
  $intercept: $min - $slope * $min-vw;
  @return calc(#{$intercept} + #{$slope * 100}vw);
}

.container {
  padding: fluid-space(16px, 48px);
}

// Practical: Modular scale
@function modular-scale($step, $base: 16px, $ratio: 1.5) {
  @return $base * math.pow($ratio, $step);
}

h1 { font-size: modular-scale(3); }   // 54px
h2 { font-size: modular-scale(2); }   // 36px
h3 { font-size: modular-scale(1); }   // 24px
Warning: The / operator is deprecated for division. Always use math.div() in Dart Sass. Plain / is used for CSS font shorthand and slash-separated values.

10.2 Comparison Operators (==, !=, <, >, <=, >=)

Operator Description Example Result
== Equal to 10px == 10px true
!= Not equal to 10px != 20px true
< Less than 5 < 10 true
> Greater than 15 > 10 true
<= Less than or equal 10 <= 10 true
>= Greater than or equal 15 >= 10 true

Example: Comparison operations

@use 'sass:color';

// Equality comparison
.equality {
  // Numbers
  $is-same: 10px == 10px;           // true
  $not-same: 10px == 20px;          // false
  
  // Strings
  $str-eq: "hello" == "hello";      // true
  $str-neq: "hello" != "world";     // true
  
  // Colors
  $color-eq: red == #ff0000;        // true
  $color-neq: red != blue;          // true
  
  // Lists
  $list-eq: (1, 2, 3) == (1, 2, 3); // true
  
  // null
  $is-null: null == null;           // true
}

// Numeric comparison
.numeric {
  // Basic comparison
  $greater: 20 > 10;                // true
  $less: 5 < 10;                    // true
  $gte: 10 >= 10;                   // true
  $lte: 10 <= 15;                   // true
  
  // With units
  $px-gt: 100px > 50px;             // true
  $rem-lt: 1rem < 2rem;             // true
}

// Conditional styling based on comparison
@mixin responsive-font($size) {
  font-size: $size;
  
  @if $size > 24px {
    line-height: 1.2;
  } @else if $size > 16px {
    line-height: 1.4;
  } @else {
    line-height: 1.6;
  }
}

.title {
  @include responsive-font(32px);  // line-height: 1.2
}

// Practical: Color brightness check
@function is-light($color) {
  @return color.lightness($color) > 50%;
}

@function contrast-color($bg) {
  @if is-light($bg) {
    @return #000;
  } @else {
    @return #fff;
  }
}

.button {
  background: #3498db;
  color: contrast-color(#3498db);   // #fff
}

// Practical: Breakpoint comparison
$breakpoints: (
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px
);

@mixin above($breakpoint) {
  $value: map.get($breakpoints, $breakpoint);
  
  @if $value {
    @media (min-width: $value) {
      @content;
    }
  }
}

.container {
  padding: 1rem;
  
  @include above(md) {
    padding: 2rem;
  }
}

// Practical: Range validation
@function clamp-value($value, $min, $max) {
  @if $value < $min {
    @return $min;
  } @else if $value > $max {
    @return $max;
  }
  @return $value;
}

.box {
  width: clamp-value(150px, 100px, 200px);  // 150px
  height: clamp-value(50px, 100px, 200px);  // 100px
  padding: clamp-value(250px, 100px, 200px); // 200px
}

10.3 Boolean Operators (and, or, not)

Operator Description Example Result
and Logical AND (both true) true and true true
or Logical OR (either true) true or false true
not Logical NOT (negation) not false true

Example: Boolean logic

@use 'sass:map';
@use 'sass:meta';

// Basic boolean operations
.boolean {
  // AND - both must be true
  $both: true and true;             // true
  $one: true and false;             // false
  
  // OR - at least one must be true
  $either: true or false;           // true
  $neither: false or false;         // false
  
  // NOT - negation
  $neg-true: not true;              // false
  $neg-false: not false;            // true
}

// Complex conditions
@mixin validate($value, $min, $max) {
  @if $value >= $min and $value <= $max {
    // Valid range
    width: $value;
  } @else {
    @error "Value must be between #{$min} and #{$max}";
  }
}

.box {
  @include validate(150px, 100px, 200px);  // OK
}

// Multiple conditions with OR
@function is-valid-color($color) {
  @return meta.type-of($color) == 'color' or $color == transparent;
}

.element {
  @if is-valid-color(red) {
    background: red;
  }
}

// NOT with comparisons
@mixin hide-on-mobile($hide) {
  @if not $hide {
    @media (max-width: 768px) {
      display: none;
    }
  }
}

// Truthiness in Sass
.truthiness {
  // Truthy: everything except false and null
  $truthy-vals: (
    0,          // truthy (unlike JavaScript!)
    "",         // truthy
    (),         // truthy
    true
  );
  
  // Falsy: only false and null
  $falsy-vals: (
    false,
    null
  );
}

// Practical: Feature detection
$enable-animations: true;
$enable-shadows: true;
$enable-gradients: false;

@mixin button-style {
  padding: 10px 20px;
  
  @if $enable-animations and $enable-shadows {
    // Both enabled
    box-shadow: 0 2px 4px rgba(0,0,0,0.2);
    transition: all 0.3s;
  } @else if $enable-animations or $enable-shadows {
    // At least one enabled
    @if $enable-animations {
      transition: all 0.3s;
    }
    @if $enable-shadows {
      box-shadow: 0 2px 4px rgba(0,0,0,0.2);
    }
  }
  
  @if not $enable-gradients {
    background: solid-color;
  }
}

// Practical: Permission checking
@function has-permission($user, $required-roles...) {
  $user-roles: map.get($user, roles);
  
  @each $role in $required-roles {
    @if list.index($user-roles, $role) {
      @return true;
    }
  }
  
  @return false;
}

$admin: (roles: (admin, editor));
$is-admin: has-permission($admin, admin, super-admin);  // true

// Practical: Validation with multiple checks
@function is-valid-size($size) {
  $is-number: meta.type-of($size) == 'number';
  $has-unit: not math.is-unitless($size);
  $in-range: $size >= 0px and $size <= 1000px;
  
  @return $is-number and $has-unit and $in-range;
}

.container {
  @if is-valid-size(200px) {
    width: 200px;
  }
}
Note: In Sass, only false and null are falsy. Unlike JavaScript, 0, "", and () are truthy.

10.4 String Concatenation and Interpolation

Operation Syntax Description Example
+ operator $str1 + $str2 Concatenate strings "hello" + "world" → "helloworld"
Interpolation #{$expression} Embed expression in string "size: #{10px}" → "size: 10px"
Selector interpolation .#{$class} Dynamic selector names .#{$prefix}-button
Property interpolation #{$prop}: value Dynamic property names #{$side}-width: 1px
Quoted strings "text" or 'text' Preserves quotes Font family names
Unquoted strings identifier No quotes in output CSS values

Example: String operations and interpolation

@use 'sass:string';

// String concatenation
.concat {
  // With + operator
  $full-name: "John" + " " + "Doe";       // "John Doe"
  
  // Quoted + unquoted
  $mixed: "font-" + family;               // "font-family"
  
  // Quote preservation (first operand)
  $quoted: "hello" + world;               // "helloworld"
  $unquoted: hello + "world";             // helloworld
}

// Interpolation in strings
.interpolation {
  $size: 16px;
  $name: "title";
  
  // In string
  font: #{$size}/1.5 Arial;               // 16px/1.5 Arial
  content: "Size is #{$size}";            // "Size is 16px"
  
  // Multiple interpolations
  $msg: "#{$name} has size #{$size}";     // "title has size 16px"
}

// Selector interpolation
$prefix: "app";

.#{$prefix}-header {                      // .app-header
  color: blue;
}

.#{$prefix}-footer {                      // .app-footer
  color: gray;
}

// Dynamic BEM modifiers
@mixin bem-modifiers($block, $modifiers...) {
  @each $modifier in $modifiers {
    &--#{$modifier} {
      @content;
    }
  }
}

.button {
  @include bem-modifiers('button', primary, large, disabled) {
    // Generates: .button--primary, .button--large, .button--disabled
    display: inline-block;
  }
}

// Property interpolation
@mixin border-style($side, $width, $color) {
  border-#{$side}-width: $width;
  border-#{$side}-color: $color;
  border-#{$side}-style: solid;
}

.box {
  @include border-style(top, 2px, red);
  // border-top-width: 2px;
  // border-top-color: red;
  // border-top-style: solid;
}

// Practical: Dynamic margin/padding
@each $side in (top, right, bottom, left) {
  @each $size, $value in (sm: 8px, md: 16px, lg: 24px) {
    .m#{string.slice($side, 1, 1)}-#{$size} {
      margin-#{$side}: $value;
    }
    
    .p#{string.slice($side, 1, 1)}-#{$size} {
      padding-#{$side}: $value;
    }
  }
}
// Generates: .mt-sm, .mt-md, .mt-lg, .pt-sm, etc.

// Practical: Icon class generator
$icons: (home, user, settings, search);

@each $icon in $icons {
  .icon-#{$icon} {
    background-image: url("icons/#{$icon}.svg");
  }
}

// Interpolation in calc()
.calc-demo {
  $base: 100px;
  $multiplier: 2;
  
  // Need interpolation in calc
  width: calc(#{$base} * #{$multiplier});
  
  // With variables
  $gap: 20px;
  width: calc(100% - #{$gap * 2});
}

// Interpolation with operations
.operations {
  $width: 100px;
  $height: 50px;
  
  // In custom properties
  --size: #{$width + $height};              // --size: 150px
  
  // In attribute selectors
  [data-size="#{$width}"] {
    width: $width;
  }
}

// Quoted string handling
.quotes {
  // Font families need quotes if spaces
  $font: "Open Sans";
  font-family: $font;                       // "Open Sans"
  
  // Unquote if needed
  font-family: string.unquote($font);       // Open Sans
  
  // Quote if needed
  $unquoted: Arial;
  font-family: string.quote($unquoted);     // "Arial"
}

// Practical: Data URI builder
@function data-uri($mime, $data) {
  @return url("data:#{$mime};base64,#{$data}");
}

.icon {
  background: data-uri('image/svg+xml', 'PHN2Zy4uLjwvc3ZnPg==');
}

10.5 Color Operations and Manipulation

Operation Syntax Description Example
Addition $c1 + $c2 Adds RGB channels #010203 + #040506 → #050709
Subtraction $c1 - $c2 Subtracts RGB channels #050709 - #040506 → #010203
Multiplication $color * $number Multiplies RGB channels #010203 * 2 → #020406
Division math.div($c, $n) Divides RGB channels div(#020406, 2) → #010203
color.scale() color.scale($c, $args) Scale properties fluidly Recommended over +/-
color.adjust() color.adjust($c, $args) Adjust by fixed amount Recommended over +/-

Example: Color arithmetic (legacy)

@use 'sass:color';
@use 'sass:math';

// DEPRECATED: Direct color arithmetic
.legacy-color-ops {
  // Addition (adds each RGB channel)
  $c1: #010203;
  $c2: #040506;
  $added: $c1 + $c2;                // #050709
  
  // Subtraction
  $subtracted: $c2 - $c1;           // #040303
  
  // Multiplication (by number)
  $doubled: #010203 * 2;            // #020406
  
  // Division
  $halved: math.div(#020406, 2);    // #010203
}

// MODERN: Use color module functions instead
.modern-color-ops {
  $base: #6b717f;
  
  // Lighten/darken (deprecated: lighten(), darken())
  $lighter: color.scale($base, $lightness: 30%);
  $darker: color.scale($base, $lightness: -30%);
  
  // Adjust specific channels
  $adjusted: color.adjust($base, $red: 20, $blue: -10);
  
  // Saturate/desaturate
  $saturated: color.scale($base, $saturation: 40%);
  $desaturated: color.scale($base, $saturation: -40%);
  
  // Transparency
  $transparent: color.adjust($base, $alpha: -0.5);
}

// Practical: Color palette generation
$primary: #007bff;

$palette: (
  primary: $primary,
  primary-light: color.scale($primary, $lightness: 20%),
  primary-lighter: color.scale($primary, $lightness: 40%),
  primary-dark: color.scale($primary, $lightness: -20%),
  primary-darker: color.scale($primary, $lightness: -40%),
  primary-pale: color.mix(white, $primary, 80%),
  primary-muted: color.scale($primary, $saturation: -60%)
);

// Practical: Tint and shade functions
@function tint($color, $percentage) {
  @return color.mix(white, $color, $percentage);
}

@function shade($color, $percentage) {
  @return color.mix(black, $color, $percentage);
}

.color-variants {
  background: tint(#007bff, 20%);     // 20% white
  border-color: shade(#007bff, 20%);  // 20% black
}

// Practical: Accessible contrast
@function contrast-ratio($c1, $c2) {
  $l1: color.lightness($c1);
  $l2: color.lightness($c2);
  
  @if $l1 > $l2 {
    @return math.div($l1, $l2);
  }
  @return math.div($l2, $l1);
}

@function accessible-color($bg, $light: white, $dark: black) {
  $light-contrast: contrast-ratio($bg, $light);
  $dark-contrast: contrast-ratio($bg, $dark);
  
  @if $light-contrast > $dark-contrast {
    @return $light;
  }
  @return $dark;
}

.button {
  $bg: #3498db;
  background: $bg;
  color: accessible-color($bg);
}

// Practical: Color temperature adjustment
@function warm($color, $amount: 10%) {
  @return color.adjust($color, $red: 20, $hue: -5deg);
}

@function cool($color, $amount: 10%) {
  @return color.adjust($color, $blue: 20, $hue: 5deg);
}

// Channel extraction and manipulation
.channel-ops {
  $color: #ff6b6b;
  
  // Extract channels
  $r: color.red($color);              // 255
  $g: color.green($color);            // 107
  $b: color.blue($color);             // 107
  
  // Modify individual channels
  $more-red: color.change($color, $red: 200);
  $more-green: color.adjust($color, $green: 50);
}
Warning: Direct color arithmetic with +, -, * is deprecated. Use color.scale(), color.adjust(), or color.change() from the sass:color module.

10.6 Unit Conversion and Calculation

Operation Description Example Notes
Compatible units Same dimension can combine 1in + 2.54cm → 2in Auto conversion
Incompatible units Different dimensions error 1px + 1em → ERROR Cannot add px and em
Unit multiplication One must be unitless 10px * 2 → 20px Creates compound units
Unit division Can cancel units div(100px, 2px) → 50 Unitless if same
math.unit() Extract unit as string unit(100px) → "px" Returns string
math.is-unitless() Check if no unit is-unitless(10) → true Boolean result
math.compatible() Check if can combine compatible(1px, 1in) → true Same dimension

Example: Unit operations and conversions

@use 'sass:math';

// Compatible unit arithmetic
.compatible {
  // Length units are compatible
  width: 1in + 2.54cm;                // 2in (cm converted)
  height: 96px + 1in;                 // 192px (1in = 96px)
  
  // Angle units
  $angle: 180deg + 3.14159rad;        // ~360deg
  
  // Time units
  $duration: 1s + 500ms;              // 1.5s
}

// Incompatible units (errors)
.incompatible {
  // width: 100px + 2em;               // ERROR: Incompatible units
  // height: 10px + 5%;                // ERROR: Cannot combine
  
  // Must use calc() for runtime calculation
  width: calc(100px + 2em);           // Valid CSS calc
  height: calc(100% - 50px);          // Valid CSS calc
}

// Multiplication and division
.math-with-units {
  // Multiplication: one operand must be unitless
  width: 10px * 2;                    // 20px (OK)
  height: 5 * 3em;                    // 15em (OK)
  // ERROR: 10px * 2px                 // Can't have px²
  
  // Division
  width: math.div(100px, 2);          // 50px
  height: math.div(100px, 2px);       // 50 (unitless - units cancel)
  
  // Percentage calculation
  $width: math.div(300px, 900px) * 100%;  // 33.333%
}

// Unit inspection
.unit-inspection {
  $value: 16px;
  
  // Get unit as string
  $unit-str: math.unit($value);       // "px"
  
  // Check if unitless
  $has-unit: math.is-unitless($value);     // false
  $no-unit: math.is-unitless(10);          // true
  
  // Check compatibility
  $can-add-px-in: math.compatible(1px, 1in);   // true (both length)
  $can-add-px-em: math.compatible(1px, 1em);   // false (different)
  $can-add-deg-rad: math.compatible(1deg, 1rad); // true (both angle)
}

// Practical: Strip unit
@function strip-unit($number) {
  @if math.is-unitless($number) {
    @return $number;
  }
  @return math.div($number, $number * 0 + 1);
}

.strip {
  $unitless: strip-unit(100px);       // 100
  $calc: $unitless * 2;               // 200
}

// Practical: Convert px to rem
@function px-to-rem($px, $base: 16px) {
  @return math.div($px, $base) * 1rem;
}

.convert {
  font-size: px-to-rem(24px);         // 1.5rem
  margin: px-to-rem(32px);            // 2rem
}

// Practical: Convert rem to px
@function rem-to-px($rem, $base: 16px) {
  @return math.div($rem, 1rem) * $base;
}

// Practical: Percentage width calculator
@function percent-width($target, $context) {
  @return math.div($target, $context) * 100%;
}

.column {
  width: percent-width(300px, 1200px);  // 25%
}

// Practical: Responsive unit converter
@function responsive-size($min, $max, $min-vw: 320px, $max-vw: 1200px) {
  // Strip units for calculation
  $min-val: strip-unit($min);
  $max-val: strip-unit($max);
  $min-vw-val: strip-unit($min-vw);
  $max-vw-val: strip-unit($max-vw);
  
  $slope: math.div($max-val - $min-val, $max-vw-val - $min-vw-val);
  $intercept: $min-val - $slope * $min-vw-val;
  
  @return calc(#{$intercept}px + #{$slope * 100}vw);
}

h1 {
  font-size: responsive-size(24px, 48px);
}

// Unit conversion constants
$px-per-inch: 96px;
$px-per-cm: math.div($px-per-inch, 2.54);
$px-per-mm: math.div($px-per-cm, 10);

@function inches-to-px($inches) {
  @return $inches * $px-per-inch;
}

// Compound units from multiplication
.compound {
  // Creates compound units
  $area: 10px * 20px;                 // 200px*px (rarely useful)
  
  // Use division to create ratios
  $ratio: math.div(16px, 1em);        // Usually use unitless numbers
}

Operators Summary

  • Arithmetic: Use math.div() instead of / for division
  • Comparison: Works with numbers, strings, colors; returns boolean
  • Boolean: Only false and null are falsy (0 is truthy!)
  • Strings: Use + for concatenation, #{} for interpolation
  • Colors: Prefer color.scale() over direct arithmetic
  • Units: Compatible units convert automatically; use calc() for incompatible
  • Operator precedence: not* / %+ -< > <= >=== !=andor
Note: Sass operators evaluate at compile time, not runtime. Use CSS calc() for runtime calculations with viewport units or mixed incompatible units.

11. Advanced Nesting and Selector Techniques

11.1 Deep Nesting and BEM Integration

Pattern Syntax Output Best Practice
BEM Block .block { } .block Top-level component
BEM Element &__element { } .block__element Part of block
BEM Modifier &--modifier { } .block--modifier Variation of block
Combined BEM &__elem--mod { } .block__elem--mod Modified element
Parent reference & { } Full parent selector Modifier contexts
Max nesting depth 3-4 levels max Avoid specificity wars Flatten if deeper

Example: BEM methodology with SCSS

// Perfect BEM with SCSS nesting
.card {
  padding: 1rem;
  background: white;
  border-radius: 8px;
  
  // BEM Element: .card__header
  &__header {
    padding: 1rem;
    border-bottom: 1px solid #ddd;
    
    // Nested element: .card__header__title
    &__title {
      font-size: 1.5rem;
      font-weight: bold;
      margin: 0;
    }
    
    &__subtitle {
      font-size: 0.875rem;
      color: #666;
    }
  }
  
  // BEM Element: .card__body
  &__body {
    padding: 1rem;
  }
  
  // BEM Element: .card__footer
  &__footer {
    padding: 1rem;
    border-top: 1px solid #ddd;
    text-align: right;
  }
  
  // BEM Modifier: .card--featured
  &--featured {
    border: 2px solid gold;
    box-shadow: 0 4px 8px rgba(0,0,0,0.2);
    
    // Modified element: .card--featured .card__header
    .card__header {
      background: gold;
    }
  }
  
  // BEM Modifier: .card--compact
  &--compact {
    padding: 0.5rem;
    
    .card__header,
    .card__body,
    .card__footer {
      padding: 0.5rem;
    }
  }
  
  // State modifier: .card.is-loading
  &.is-loading {
    opacity: 0.5;
    pointer-events: none;
  }
}

// Alternative: Element modifiers
.button {
  display: inline-block;
  padding: 10px 20px;
  
  // Element: .button__icon
  &__icon {
    margin-right: 8px;
    
    // Element modifier: .button__icon--left
    &--left {
      margin-right: 8px;
      margin-left: 0;
    }
    
    // Element modifier: .button__icon--right
    &--right {
      margin-left: 8px;
      margin-right: 0;
    }
  }
  
  // Modifier: .button--primary
  &--primary {
    background: blue;
    color: white;
  }
  
  // Modifier: .button--large
  &--large {
    padding: 15px 30px;
    font-size: 1.2rem;
  }
}

// Advanced: BEM with state classes
.nav {
  display: flex;
  
  &__item {
    padding: 10px 20px;
    
    // Combined: .nav__item--active
    &--active {
      background: blue;
      color: white;
    }
    
    // State: .nav__item.is-disabled
    &.is-disabled {
      opacity: 0.5;
      pointer-events: none;
    }
    
    // Pseudo-class: .nav__item:hover
    &:hover:not(.is-disabled) {
      background: lightblue;
    }
  }
}

// Practical: BEM mixin generator
@mixin element($name) {
  &__#{$name} {
    @content;
  }
}

@mixin modifier($name) {
  &--#{$name} {
    @content;
  }
}

.menu {
  display: flex;
  
  @include element(item) {
    padding: 10px;
    
    @include modifier(active) {
      background: blue;
      color: white;
    }
  }
}

// Output:
// .menu { display: flex; }
// .menu__item { padding: 10px; }
// .menu__item--active { background: blue; color: white; }

// Nesting depth warning (BAD - too deep)
.header {
  .container {
    .nav {
      .menu {
        .item {
          .link {
            // 6 levels - TOO DEEP!
            color: blue;
          }
        }
      }
    }
  }
}

// Better: Flatten with BEM
.header { }
.header__nav { }
.header__menu { }
.header__menu-item { }
.header__menu-link { color: blue; }

11.2 Selector Functions for Dynamic Generation

Function Use Case Example Output
selector.nest() Programmatic nesting nest('.a', '.b') .a .b
selector.append() Compound selectors append('.a', ':hover') .a:hover
selector.replace() Selector transformation replace('.old', '.new') Replace part
selector.unify() Combine selectors unify('div', '.class') div.class
& in string Parent interpolation #{&}--modifier Dynamic BEM

Example: Dynamic selector generation

@use 'sass:selector';
@use 'sass:list';

// Dynamic BEM modifier generator
@mixin bem-modifiers($modifiers...) {
  @each $modifier in $modifiers {
    &--#{$modifier} {
      @content ($modifier);
    }
  }
}

.button {
  padding: 10px 20px;
  
  @include bem-modifiers(primary, secondary, danger) using ($mod) {
    @if $mod == primary {
      background: blue;
    } @else if $mod == secondary {
      background: gray;
    } @else if $mod == danger {
      background: red;
    }
  }
}

// Selector nesting with functions
.dynamic-nest {
  $parent: '.container';
  $child: '.item';
  
  // Programmatic nesting
  #{selector.nest($parent, $child)} {
    display: block;
  }
  // Outputs: .container .item { display: block; }
}

// Append pseudo-classes
@mixin hover-focus {
  $selector: &;
  
  #{selector.append($selector, ':hover')},
  #{selector.append($selector, ':focus')} {
    @content;
  }
}

.link {
  color: blue;
  
  @include hover-focus {
    color: darkblue;
    text-decoration: underline;
  }
}

// Generate utility classes dynamically
$sides: (top, right, bottom, left);
$sizes: (sm: 8px, md: 16px, lg: 24px, xl: 32px);

@each $side in $sides {
  @each $size-name, $size-value in $sizes {
    .m-#{$side}-#{$size-name} {
      margin-#{$side}: $size-value;
    }
    
    .p-#{$side}-#{$size-name} {
      padding-#{$side}: $size-value;
    }
  }
}

// Advanced: Context-aware selectors
@mixin theme-context($themes...) {
  @each $theme in $themes {
    .theme-#{$theme} & {
      @content ($theme);
    }
  }
}

.card {
  background: white;
  
  @include theme-context(dark, high-contrast) using ($theme) {
    @if $theme == dark {
      background: #333;
      color: white;
    } @else if $theme == high-contrast {
      background: black;
      color: yellow;
      border: 2px solid yellow;
    }
  }
}
// Outputs:
// .theme-dark .card { background: #333; color: white; }
// .theme-high-contrast .card { background: black; color: yellow; ... }

// Practical: Responsive state variants
@mixin variants($variants...) {
  @each $variant in $variants {
    &-#{$variant} {
      @content ($variant);
    }
  }
}

.text {
  @include variants(center, left, right) using ($align) {
    text-align: $align;
  }
}

// Selector replacement
$old-prefix: 'btn';
$new-prefix: 'button';

@function migrate-selector($selector) {
  @return selector.replace($selector, '.#{$old-prefix}', '.#{$new-prefix}');
}

// Practical: Attribute selector generator
@mixin data-state($states...) {
  @each $state in $states {
    &[data-state="#{$state}"] {
      @content ($state);
    }
  }
}

.component {
  @include data-state(loading, error, success) using ($state) {
    @if $state == loading {
      opacity: 0.5;
    } @else if $state == error {
      border-color: red;
    } @else if $state == success {
      border-color: green;
    }
  }
}

11.3 Pseudo-selector Nesting Patterns

Pattern Syntax Output Use Case
:hover &:hover { } .element:hover Mouse over state
:focus &:focus { } .element:focus Keyboard focus
:active &:active { } .element:active Click/press state
::before/::after &::before { } .element::before Pseudo-elements
:not() &:not(.class) { } .element:not(.class) Exclusion selector
:nth-child() &:nth-child(n) { } .element:nth-child(n) Positional selection
Combined &:hover:not(:disabled) Multiple pseudos Complex states

Example: Pseudo-selector patterns

// Interactive states
.button {
  background: blue;
  color: white;
  transition: all 0.3s;
  
  // Hover state
  &:hover {
    background: darkblue;
    transform: translateY(-2px);
  }
  
  // Focus state (accessibility)
  &:focus {
    outline: 2px solid orange;
    outline-offset: 2px;
  }
  
  // Active (pressed) state
  &:active {
    transform: translateY(0);
    box-shadow: inset 0 2px 4px rgba(0,0,0,0.3);
  }
  
  // Disabled state
  &:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    
    // No hover when disabled
    &:hover {
      background: blue;
      transform: none;
    }
  }
  
  // Combined: hover but not disabled
  &:hover:not(:disabled) {
    cursor: pointer;
  }
  
  // Focus-visible (modern accessibility)
  &:focus-visible {
    outline: 2px solid orange;
  }
  
  &:focus:not(:focus-visible) {
    outline: none;
  }
}

// Pseudo-elements
.card {
  position: relative;
  
  // Before pseudo-element
  &::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 4px;
    background: linear-gradient(90deg, blue, purple);
  }
  
  // After pseudo-element
  &::after {
    content: '→';
    margin-left: 8px;
    transition: margin-left 0.3s;
  }
  
  &:hover::after {
    margin-left: 12px;
  }
}

// Structural pseudo-classes
.list {
  &__item {
    padding: 10px;
    border-bottom: 1px solid #ddd;
    
    // First child
    &:first-child {
      border-top: 1px solid #ddd;
    }
    
    // Last child
    &:last-child {
      border-bottom: none;
    }
    
    // Nth child patterns
    &:nth-child(odd) {
      background: #f9f9f9;
    }
    
    &:nth-child(even) {
      background: white;
    }
    
    // Every 3rd item
    &:nth-child(3n) {
      font-weight: bold;
    }
    
    // First 3 items
    &:nth-child(-n + 3) {
      border-left: 3px solid blue;
    }
    
    // Last 2 items
    &:nth-last-child(-n + 2) {
      opacity: 0.7;
    }
  }
}

// Form pseudo-classes
.input {
  padding: 10px;
  border: 1px solid #ccc;
  
  &:focus {
    border-color: blue;
    box-shadow: 0 0 0 3px rgba(0,0,255,0.1);
  }
  
  &:valid {
    border-color: green;
  }
  
  &:invalid {
    border-color: red;
  }
  
  &:required {
    border-left: 3px solid orange;
  }
  
  &:disabled {
    background: #f5f5f5;
    cursor: not-allowed;
  }
  
  &:read-only {
    background: #f9f9f9;
  }
  
  &:placeholder-shown {
    border-style: dashed;
  }
  
  &::placeholder {
    color: #999;
    font-style: italic;
  }
}

// Link states (LVHA order)
.link {
  color: blue;
  text-decoration: none;
  
  // L - Link (unvisited)
  &:link {
    color: blue;
  }
  
  // V - Visited
  &:visited {
    color: purple;
  }
  
  // H - Hover
  &:hover {
    color: darkblue;
    text-decoration: underline;
  }
  
  // A - Active
  &:active {
    color: red;
  }
}

// Practical: Hover/focus mixin
@mixin interactive-state {
  &:hover,
  &:focus {
    @content;
  }
}

.card {
  @include interactive-state {
    box-shadow: 0 4px 8px rgba(0,0,0,0.2);
    transform: translateY(-2px);
  }
}

// Practical: Not disabled mixin
@mixin when-enabled {
  &:not(:disabled):not(.is-disabled) {
    @content;
  }
}

.button {
  @include when-enabled {
    cursor: pointer;
    
    &:hover {
      background: darkblue;
    }
  }
}

// CSS :has() and :is() (modern)
.card {
  // Has child selector
  &:has(> .card__image) {
    padding-top: 0;
  }
  
  // Is selector (shorthand)
  &:is(:hover, :focus) {
    outline: 2px solid blue;
  }
  
  // Where (zero specificity)
  &:where(:hover, :focus) {
    opacity: 0.9;
  }
}

11.4 Media Query Nesting and Responsive Mixins

Pattern Syntax Description Best Practice
Nested @media @media (min-width) { } Inside selector Keeps context together
Breakpoint mixin @include bp(md) { } Named breakpoints Consistent breakpoints
Mobile-first min-width Base → larger Preferred approach
Desktop-first max-width Desktop → smaller Legacy approach
Range queries min and max Between breakpoints Specific targeting

Example: Responsive design with nested media queries

@use 'sass:map';

// Breakpoint configuration
$breakpoints: (
  xs: 0,
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px,
  xxl: 1400px
);

// Mobile-first mixin (min-width)
@mixin above($breakpoint) {
  $value: map.get($breakpoints, $breakpoint);
  
  @if $value {
    @media (min-width: $value) {
      @content;
    }
  } @else {
    @media (min-width: $breakpoint) {
      @content;
    }
  }
}

// Desktop-first mixin (max-width)
@mixin below($breakpoint) {
  $value: map.get($breakpoints, $breakpoint);
  
  @if $value {
    @media (max-width: $value - 1px) {
      @content;
    }
  } @else {
    @media (max-width: $breakpoint) {
      @content;
    }
  }
}

// Between two breakpoints
@mixin between($min, $max) {
  $min-val: map.get($breakpoints, $min) or $min;
  $max-val: map.get($breakpoints, $max) or $max;
  
  @media (min-width: $min-val) and (max-width: $max-val - 1px) {
    @content;
  }
}

// Nested media queries example
.container {
  width: 100%;
  padding: 1rem;
  
  // Mobile-first responsive design
  @include above(sm) {
    max-width: 540px;
    margin: 0 auto;
  }
  
  @include above(md) {
    max-width: 720px;
    padding: 1.5rem;
  }
  
  @include above(lg) {
    max-width: 960px;
    padding: 2rem;
  }
  
  @include above(xl) {
    max-width: 1140px;
  }
  
  @include above(xxl) {
    max-width: 1320px;
  }
}

// Responsive typography
.heading {
  font-size: 1.5rem;
  line-height: 1.2;
  
  @include above(md) {
    font-size: 2rem;
  }
  
  @include above(lg) {
    font-size: 2.5rem;
  }
  
  @include above(xl) {
    font-size: 3rem;
    line-height: 1.1;
  }
}

// Responsive grid
.grid {
  display: grid;
  gap: 1rem;
  
  // Mobile: 1 column
  grid-template-columns: 1fr;
  
  // Tablet: 2 columns
  @include above(md) {
    grid-template-columns: repeat(2, 1fr);
    gap: 1.5rem;
  }
  
  // Desktop: 3 columns
  @include above(lg) {
    grid-template-columns: repeat(3, 1fr);
    gap: 2rem;
  }
  
  // Large desktop: 4 columns
  @include above(xl) {
    grid-template-columns: repeat(4, 1fr);
  }
}

// Only for specific range
.sidebar {
  display: none;
  
  // Only show between md and lg
  @include between(md, lg) {
    display: block;
    width: 200px;
  }
  
  @include above(lg) {
    display: block;
    width: 250px;
  }
}

// Media query nesting with elements
.card {
  padding: 1rem;
  
  &__image {
    width: 100%;
    height: 200px;
    
    @include above(md) {
      height: 300px;
    }
  }
  
  &__title {
    font-size: 1.25rem;
    
    @include above(md) {
      font-size: 1.5rem;
    }
  }
}

// Advanced: Orientation queries
@mixin landscape {
  @media (orientation: landscape) {
    @content;
  }
}

@mixin portrait {
  @media (orientation: portrait) {
    @content;
  }
}

.video-player {
  aspect-ratio: 16/9;
  
  @include portrait {
    aspect-ratio: 4/3;
  }
}

// Advanced: Custom media features
@mixin prefers-dark-mode {
  @media (prefers-color-scheme: dark) {
    @content;
  }
}

@mixin prefers-reduced-motion {
  @media (prefers-reduced-motion: reduce) {
    @content;
  }
}

.theme {
  background: white;
  color: black;
  
  @include prefers-dark-mode {
    background: #1a1a1a;
    color: white;
  }
}

.animated {
  transition: all 0.3s;
  
  @include prefers-reduced-motion {
    transition: none;
  }
}

// Container queries (modern)
@mixin container($size) {
  @container (min-width: $size) {
    @content;
  }
}

.card {
  container-type: inline-size;
  
  &__title {
    font-size: 1rem;
    
    @include container(400px) {
      font-size: 1.5rem;
    }
    
    @include container(600px) {
      font-size: 2rem;
    }
  }
}

11.5 Keyframe Animation Nesting

Pattern Syntax Description Use Case
@keyframes @keyframes name { } Define animation Reusable animations
Dynamic names @keyframes #{$name} Generated keyframes Loop-based creation
Nested in selector Inside component Scoped animations Component-specific
Percentage steps 0%, 50%, 100% Animation timeline Multi-step animations
from/to from { } to { } Start and end Simple animations

Example: Keyframe animations in SCSS

// Basic keyframe definition
@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.fade-in {
  animation: fadeIn 0.5s ease-in;
}

// Multi-step keyframes
@keyframes slideInBounce {
  0% {
    transform: translateX(-100%);
    opacity: 0;
  }
  60% {
    transform: translateX(10px);
    opacity: 1;
  }
  80% {
    transform: translateX(-5px);
  }
  100% {
    transform: translateX(0);
  }
}

// Dynamic keyframe generation
$animations: (
  fadeIn: (from: (opacity: 0), to: (opacity: 1)),
  slideDown: (from: (transform: translateY(-20px)), to: (transform: translateY(0))),
  scaleUp: (from: (transform: scale(0.8)), to: (transform: scale(1)))
);

@each $name, $steps in $animations {
  @keyframes #{$name} {
    from {
      @each $prop, $value in map.get($steps, from) {
        #{$prop}: $value;
      }
    }
    to {
      @each $prop, $value in map.get($steps, to) {
        #{$prop}: $value;
      }
    }
  }
}

// Scoped animations (nested in component)
.loader {
  // Keyframes defined within component scope
  @keyframes loader-spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
  }
  
  width: 50px;
  height: 50px;
  border: 3px solid #f3f3f3;
  border-top: 3px solid blue;
  border-radius: 50%;
  animation: loader-spin 1s linear infinite;
}

// Complex multi-property animation
@keyframes pulse {
  0% {
    transform: scale(1);
    box-shadow: 0 0 0 0 rgba(0, 123, 255, 0.7);
  }
  50% {
    transform: scale(1.05);
    box-shadow: 0 0 0 10px rgba(0, 123, 255, 0);
  }
  100% {
    transform: scale(1);
    box-shadow: 0 0 0 0 rgba(0, 123, 255, 0);
  }
}

// Animation mixin
@mixin animate($name, $duration: 1s, $timing: ease, $iteration: 1) {
  animation-name: $name;
  animation-duration: $duration;
  animation-timing-function: $timing;
  animation-iteration-count: $iteration;
}

.button {
  @include animate(pulse, 2s, ease-out, infinite);
}

// Generate bounce animations
@for $i from 1 through 3 {
  @keyframes bounce-#{$i} {
    0%, 100% {
      transform: translateY(0);
    }
    50% {
      transform: translateY(-#{$i * 10}px);
    }
  }
  
  .bounce-#{$i} {
    animation: bounce-#{$i} 0.6s ease-in-out infinite;
  }
}

// Practical: Loading dots animation
@keyframes dot-pulse {
  0%, 80%, 100% {
    opacity: 0.3;
    transform: scale(0.8);
  }
  40% {
    opacity: 1;
    transform: scale(1);
  }
}

.loading-dots {
  display: flex;
  gap: 8px;
  
  &__dot {
    width: 10px;
    height: 10px;
    background: blue;
    border-radius: 50%;
    animation: dot-pulse 1.4s infinite ease-in-out;
    
    &:nth-child(1) {
      animation-delay: 0s;
    }
    
    &:nth-child(2) {
      animation-delay: 0.2s;
    }
    
    &:nth-child(3) {
      animation-delay: 0.4s;
    }
  }
}

// Practical: Slide animations from directions
$directions: (
  left: translateX(-100%),
  right: translateX(100%),
  top: translateY(-100%),
  bottom: translateY(100%)
);

@each $direction, $transform in $directions {
  @keyframes slideIn-#{$direction} {
    from {
      transform: $transform;
      opacity: 0;
    }
    to {
      transform: translate(0, 0);
      opacity: 1;
    }
  }
  
  .slide-in-#{$direction} {
    animation: slideIn-#{$direction} 0.5s ease-out;
  }
}

11.6 At-rule Nesting and CSS Grid/Flexbox

At-rule Nesting Pattern Description Use Case
@media Inside selectors Responsive styles Component breakpoints
@supports Feature detection Progressive enhancement Modern CSS features
@container Container queries Size-based styling Component-level responsive
@layer Cascade layers Style ordering Specificity control
Grid nesting display: grid children Grid layouts Complex layouts
Flex nesting display: flex children Flexbox layouts 1D layouts

Example: At-rule nesting and layout systems

// @supports nesting
.card {
  display: block;
  
  // Feature detection
  @supports (display: grid) {
    display: grid;
    grid-template-columns: 1fr 2fr;
    gap: 1rem;
  }
  
  // Fallback for older browsers
  @supports not (display: grid) {
    display: flex;
    flex-wrap: wrap;
  }
}

// @supports with multiple features
.modern-layout {
  display: block;
  
  @supports (display: grid) and (gap: 1rem) {
    display: grid;
    gap: 1rem;
  }
  
  @supports (container-type: inline-size) {
    container-type: inline-size;
  }
}

// Nested grid system
.grid-container {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 1rem;
  
  &__item {
    // Default: full width (mobile)
    grid-column: span 12;
    
    // Tablet: half width
    @media (min-width: 768px) {
      grid-column: span 6;
    }
    
    // Desktop: third width
    @media (min-width: 992px) {
      grid-column: span 4;
    }
    
    // Modifiers
    &--full {
      grid-column: 1 / -1;
    }
    
    &--half {
      @media (min-width: 768px) {
        grid-column: span 6;
      }
    }
  }
}

// Flexbox utilities with nesting
.flex {
  display: flex;
  
  // Direction modifiers
  &--row {
    flex-direction: row;
  }
  
  &--column {
    flex-direction: column;
  }
  
  // Justify content
  &--center {
    justify-content: center;
  }
  
  &--between {
    justify-content: space-between;
  }
  
  &--around {
    justify-content: space-around;
  }
  
  // Align items
  &--items-center {
    align-items: center;
  }
  
  &--items-start {
    align-items: flex-start;
  }
  
  &--items-end {
    align-items: flex-end;
  }
  
  // Responsive direction
  &--responsive {
    flex-direction: column;
    
    @media (min-width: 768px) {
      flex-direction: row;
    }
  }
}

// Container queries (modern CSS)
.card-container {
  container-type: inline-size;
  container-name: card;
  
  .card {
    padding: 1rem;
    
    // When container is at least 400px
    @container card (min-width: 400px) {
      display: grid;
      grid-template-columns: 150px 1fr;
      gap: 1rem;
      padding: 1.5rem;
    }
    
    // When container is at least 600px
    @container card (min-width: 600px) {
      grid-template-columns: 200px 1fr 200px;
      padding: 2rem;
    }
  }
}

// @layer for cascade control
@layer base, components, utilities;

@layer base {
  .button {
    padding: 10px 20px;
    border: none;
  }
}

@layer components {
  .button {
    &--primary {
      background: blue;
      color: white;
    }
  }
}

@layer utilities {
  .button {
    &.rounded {
      border-radius: 9999px;
    }
  }
}

// Practical: Responsive grid mixin
@mixin grid-columns($mobile: 1, $tablet: 2, $desktop: 3, $wide: 4) {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat($mobile, 1fr);
  
  @media (min-width: 768px) {
    grid-template-columns: repeat($tablet, 1fr);
    gap: 1.5rem;
  }
  
  @media (min-width: 992px) {
    grid-template-columns: repeat($desktop, 1fr);
    gap: 2rem;
  }
  
  @media (min-width: 1200px) {
    grid-template-columns: repeat($wide, 1fr);
  }
}

.product-grid {
  @include grid-columns(1, 2, 3, 4);
}

// Practical: Flex utilities generator
@each $justify in (start, center, end, between, around) {
  .justify-#{$justify} {
    display: flex;
    justify-content: if($justify == between, space-between,
                      if($justify == around, space-around, 
                      flex-#{$justify}));
  }
}

@each $align in (start, center, end, stretch) {
  .items-#{$align} {
    display: flex;
    align-items: if($align == start or $align == end, 
                   flex-#{$align}, 
                   $align);
  }
}

// Advanced: Subgrid support
.article-layout {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 2rem;
  
  &__sidebar {
    grid-column: 1 / 4;
  }
  
  &__content {
    grid-column: 4 / -1;
    
    // Subgrid for nested content
    @supports (grid-template-columns: subgrid) {
      display: grid;
      grid-template-columns: subgrid;
      gap: 1rem;
    }
  }
}

Advanced Nesting Summary

  • BEM: Use &__element and &--modifier for clean BEM syntax
  • Max depth: Limit nesting to 3-4 levels to avoid specificity issues
  • Pseudo-selectors: Nest :hover, :focus, ::before with &
  • Media queries: Nest inside selectors for context-aware responsive design
  • Keyframes: Can be nested in components or generated dynamically
  • At-rules: @supports, @container, @layer work with nesting
  • Grid/Flex: Use nesting with modifiers for layout variations
Warning: Deep nesting increases specificity and makes styles harder to override. Keep nesting shallow and use BEM for flat, maintainable selectors.

12. File Organization and Import Strategies

12.1 Partial Files and Underscore Naming Convention

Pattern Naming Description Purpose
Partial file _filename.scss Underscore prefix Not compiled standalone
Main file main.scss No underscore Entry point, compiled
@use partial @use 'filename' Omit underscore and .scss Modern import
@import partial @import 'filename' Legacy import (deprecated) Avoid in new code
Variables partial _variables.scss Global variables Shared configuration
Mixins partial _mixins.scss Reusable mixins Shared utilities

Example: Partial files organization

// File structure
scss/
├── main.scss              // Entry point (compiled)
├── _variables.scss        // Partial (not compiled)
├── _mixins.scss           // Partial
├── _functions.scss        // Partial
└── _reset.scss            // Partial

// _variables.scss (partial)
// This file won't be compiled to CSS on its own
$primary-color: #007bff;
$secondary-color: #6c757d;
$font-stack: 'Helvetica', Arial, sans-serif;
$spacing-unit: 8px;

// _mixins.scss (partial)
@mixin flex-center {
  display: flex;
  justify-content: center;
  align-items: center;
}

@mixin responsive-font($min, $max) {
  font-size: clamp(#{$min}, 2.5vw, #{$max});
}

// _functions.scss (partial)
@use 'sass:math';

@function spacing($multiplier) {
  @return $spacing-unit * $multiplier;
}

// main.scss (entry point - will be compiled)
// Modern approach with @use
@use 'variables' as vars;
@use 'mixins' as mx;
@use 'functions' as fn;
@use 'reset';

// Now use the imported modules
.container {
  color: vars.$primary-color;
  padding: fn.spacing(2);  // 16px
  
  @include mx.flex-center;
}

// Legacy approach with @import (DEPRECATED)
// @import 'variables';
// @import 'mixins';
// @import 'functions';
// @import 'reset';

// Naming conventions
scss/
├── _btn-primary.scss      // Component partial
├── _btn-secondary.scss
├── _card-default.scss
├── _card-featured.scss
└── buttons.scss           // Compiled: imports all btn-* partials

// buttons.scss
@use 'btn-primary';
@use 'btn-secondary';

// Partial with configuration
// _button.scss
$-default-padding: 10px 20px !default;  // Private variable
$button-radius: 4px !default;           // Public variable

.button {
  padding: $-default-padding;
  border-radius: $button-radius;
}

// Using configured partial
@use 'button' with (
  $button-radius: 8px
);

// Multiple partials in subdirectories
scss/
├── base/
│   ├── _reset.scss
│   ├── _typography.scss
│   └── _variables.scss
├── components/
│   ├── _buttons.scss
│   ├── _cards.scss
│   └── _forms.scss
└── main.scss

// main.scss
@use 'base/variables';
@use 'base/reset';
@use 'base/typography';
@use 'components/buttons';
@use 'components/cards';
@use 'components/forms';
Note: Partials (files starting with _) are not compiled to CSS files directly. They must be imported into a main file that doesn't have an underscore.

12.2 Import Order and Dependency Management

Order Category Files Reason
1st Configuration Variables, functions Used by everything
2nd Utilities Mixins, helpers Reusable tools
3rd Base/Reset Normalize, reset, typography Foundation styles
4th Layout Grid, containers Page structure
5th Components Buttons, cards, forms UI elements
6th Pages Page-specific styles Specific overrides
7th Themes Dark mode, variants Theme overrides
8th Utilities Helper classes Highest specificity

Example: Proper import order

// main.scss - Correct import order

// 1. Configuration (variables must come first)
@use 'config/variables' as vars;
@use 'config/functions' as fn;

// 2. Utilities (mixins use variables)
@use 'utilities/mixins' as mx;
@use 'utilities/helpers';

// 3. Vendors/Third-party (before base styles)
@use 'vendors/normalize';
@use 'vendors/bootstrap-grid';

// 4. Base styles (foundation)
@use 'base/reset';
@use 'base/typography';
@use 'base/forms';

// 5. Layout (structural elements)
@use 'layout/grid';
@use 'layout/header';
@use 'layout/footer';
@use 'layout/sidebar';

// 6. Components (UI elements)
@use 'components/buttons';
@use 'components/cards';
@use 'components/modals';
@use 'components/navigation';
@use 'components/forms';

// 7. Pages (page-specific styles)
@use 'pages/home';
@use 'pages/about';
@use 'pages/contact';

// 8. Themes (variants and modes)
@use 'themes/dark';
@use 'themes/high-contrast';

// 9. Utilities (override everything)
@use 'utilities/spacing';
@use 'utilities/text';
@use 'utilities/display';

// Dependency example - WRONG order
// @use 'components/buttons';  // Uses variables
// @use 'config/variables';    // Defined after use - ERROR!

// Dependency example - CORRECT order
@use 'config/variables';
@use 'components/buttons';  // Now variables are available

// Namespace management
@use 'config/variables' as v;
@use 'utilities/mixins' as m;
@use 'utilities/functions' as f;

.container {
  color: v.$primary;
  padding: f.spacing(2);
  @include m.flex-center;
}

// Avoiding namespace with *
@use 'config/variables' as *;

.button {
  // No prefix needed
  background: $primary-color;
  padding: $spacing-unit * 2;
}

// Dependency tree example
// _variables.scss (no dependencies)
$primary: blue;

// _functions.scss (depends on variables)
@use 'variables' as vars;

@function get-primary() {
  @return vars.$primary;
}

// _mixins.scss (depends on functions and variables)
@use 'variables' as vars;
@use 'functions' as fn;

@mixin primary-button {
  background: fn.get-primary();
  padding: vars.$spacing-unit;
}

// _buttons.scss (depends on mixins)
@use 'mixins' as mx;

.button {
  @include mx.primary-button;
}

// Conditional imports based on environment
$environment: 'production' !default;

@if $environment == 'development' {
  @use 'dev/debug';
  @use 'dev/grid-overlay';
} @else if $environment == 'production' {
  @use 'prod/optimized';
}

// Import with configuration
@use 'config/variables' with (
  $primary-color: #ff0000,
  $font-size: 18px
);

// Forward for re-exporting (create API)
// _index.scss in utilities/
@forward 'mixins';
@forward 'functions';
@forward 'helpers';

// main.scss
@use 'utilities';  // Gets all forwarded items

12.3 File Structure Patterns (7-1 Architecture)

Folder Purpose Example Files Description
abstracts/ Variables, mixins, functions _variables.scss, _mixins.scss No CSS output
base/ Resets, typography, base _reset.scss, _typography.scss Foundation styles
components/ UI components _button.scss, _card.scss Reusable components
layout/ Page structure _header.scss, _grid.scss Major sections
pages/ Page-specific styles _home.scss, _about.scss Per-page overrides
themes/ Theme variations _dark.scss, _admin.scss Theme switches
vendors/ Third-party CSS _normalize.scss, _bootstrap.scss External libraries

Example: 7-1 Architecture pattern

// Complete 7-1 folder structure
scss/
├── abstracts/
│   ├── _variables.scss     // Global variables
│   ├── _functions.scss     // Sass functions
│   ├── _mixins.scss        // Sass mixins
│   └── _placeholders.scss  // Sass placeholders
├── base/
│   ├── _reset.scss         // Reset/normalize
│   ├── _typography.scss    // Typography rules
│   ├── _animations.scss    // Keyframes
│   └── _utilities.scss     // Utility classes
├── components/
│   ├── _buttons.scss       // Button styles
│   ├── _cards.scss         // Card component
│   ├── _carousel.scss      // Carousel
│   ├── _dropdown.scss      // Dropdown
│   ├── _forms.scss         // Form elements
│   ├── _modal.scss         // Modal dialog
│   ├── _navigation.scss    // Navigation
│   └── _table.scss         // Tables
├── layout/
│   ├── _grid.scss          // Grid system
│   ├── _header.scss        // Header
│   ├── _footer.scss        // Footer
│   ├── _sidebar.scss       // Sidebar
│   └── _containers.scss    // Containers
├── pages/
│   ├── _home.scss          // Home page
│   ├── _about.scss         // About page
│   ├── _contact.scss       // Contact page
│   └── _dashboard.scss     // Dashboard
├── themes/
│   ├── _dark.scss          // Dark theme
│   ├── _light.scss         // Light theme
│   └── _admin.scss         // Admin theme
├── vendors/
│   ├── _normalize.scss     // Normalize.css
│   └── _bootstrap.scss     // Bootstrap subset
└── main.scss               // Main entry file

// main.scss - The "1" file in 7-1
@charset 'utf-8';

// 1. Abstracts
@use 'abstracts/variables' as vars;
@use 'abstracts/functions' as fn;
@use 'abstracts/mixins' as mx;
@use 'abstracts/placeholders';

// 2. Vendors
@use 'vendors/normalize';

// 3. Base
@use 'base/reset';
@use 'base/typography';
@use 'base/animations';
@use 'base/utilities';

// 4. Layout
@use 'layout/grid';
@use 'layout/header';
@use 'layout/footer';
@use 'layout/sidebar';
@use 'layout/containers';

// 5. Components
@use 'components/buttons';
@use 'components/cards';
@use 'components/carousel';
@use 'components/dropdown';
@use 'components/forms';
@use 'components/modal';
@use 'components/navigation';
@use 'components/table';

// 6. Pages
@use 'pages/home';
@use 'pages/about';
@use 'pages/contact';
@use 'pages/dashboard';

// 7. Themes
@use 'themes/dark';
@use 'themes/light';

// Alternative: Atomic Design structure
scss/
├── 00-settings/
│   └── _variables.scss
├── 01-tools/
│   ├── _functions.scss
│   └── _mixins.scss
├── 02-generic/
│   └── _normalize.scss
├── 03-elements/
│   ├── _headings.scss
│   └── _links.scss
├── 04-objects/
│   ├── _container.scss
│   └── _grid.scss
├── 05-components/
│   ├── _button.scss
│   └── _card.scss
├── 06-utilities/
│   └── _spacing.scss
└── main.scss

// Alternative: Component-based structure (React/Vue)
src/
├── components/
│   ├── Button/
│   │   ├── Button.tsx
│   │   ├── Button.scss
│   │   └── index.ts
│   ├── Card/
│   │   ├── Card.tsx
│   │   ├── Card.scss
│   │   └── index.ts
│   └── ...
├── styles/
│   ├── abstracts/
│   ├── base/
│   └── global.scss
└── App.scss

// Alternative: Feature-based structure
scss/
├── core/               // Shared across features
│   ├── _variables.scss
│   ├── _mixins.scss
│   └── _base.scss
├── features/
│   ├── auth/
│   │   ├── _login.scss
│   │   └── _register.scss
│   ├── dashboard/
│   │   ├── _widgets.scss
│   │   └── _charts.scss
│   └── products/
│       ├── _list.scss
│       └── _detail.scss
└── main.scss

// Minimal structure (small projects)
scss/
├── _variables.scss
├── _mixins.scss
├── _base.scss
├── _layout.scss
├── _components.scss
└── main.scss

12.4 Index Files and Barrel Exports

Pattern Syntax Purpose Benefit
Index file _index.scss Folder entry point Clean imports
@forward @forward 'file' Re-export module Create public API
@use 'folder' Import index Auto-loads _index.scss Shorter paths
Prefix stripping @forward ... hide $-private Hide private members Encapsulation
Namespace @forward ... as name-* Add prefix Avoid conflicts

Example: Index files and barrel patterns

// Folder structure with index files
components/
├── _index.scss         // Barrel export
├── _button.scss
├── _card.scss
└── _modal.scss

// components/_index.scss
// Forward all components from this folder
@forward 'button';
@forward 'card';
@forward 'modal';

// main.scss
// Instead of importing each component:
// @use 'components/button';
// @use 'components/card';
// @use 'components/modal';

// Just import the index:
@use 'components';

// Advanced: Selective forwarding
// components/_index.scss
@forward 'button';
@forward 'card';
// Don't forward modal (keep it private to components)

// Advanced: Forward with prefix
// components/_index.scss
@forward 'button' as btn-*;
@forward 'card' as card-*;

// Usage
@use 'components' as c;

.element {
  @include c.btn-primary;
  @include c.card-layout;
}

// Advanced: Forward with hiding
// abstracts/_variables.scss
$primary: blue;
$-internal-spacing: 8px;  // Private (starts with -)

// abstracts/_index.scss
@forward 'variables' hide $-internal-spacing;

// main.scss
@use 'abstracts' as abs;

.button {
  color: abs.$primary;           // ✓ Works
  // padding: abs.$-internal-spacing;  // ✗ Error: private
}

// Nested index files
scss/
├── base/
│   ├── _index.scss
│   ├── _reset.scss
│   └── _typography.scss
├── components/
│   ├── _index.scss
│   ├── buttons/
│   │   ├── _index.scss
│   │   ├── _primary.scss
│   │   └── _secondary.scss
│   └── cards/
│       ├── _index.scss
│       ├── _default.scss
│       └── _featured.scss
└── main.scss

// components/buttons/_index.scss
@forward 'primary';
@forward 'secondary';

// components/cards/_index.scss
@forward 'default';
@forward 'featured';

// components/_index.scss
@forward 'buttons';
@forward 'cards';

// main.scss
@use 'components';  // Gets everything!

// Practical: Theme API with index
themes/
├── _index.scss
├── _dark.scss
├── _light.scss
└── _high-contrast.scss

// themes/_index.scss
@forward 'dark' as dark-*;
@forward 'light' as light-*;
@forward 'high-contrast' as hc-*;

// Or selective theme forwarding
$active-theme: 'dark' !default;

@if $active-theme == 'dark' {
  @forward 'dark';
} @else if $active-theme == 'light' {
  @forward 'light';
} @else {
  @forward 'high-contrast';
}

// Practical: Utilities barrel
utilities/
├── _index.scss
├── _spacing.scss
├── _text.scss
├── _colors.scss
└── _display.scss

// utilities/_index.scss
@forward 'spacing';
@forward 'text';
@forward 'colors';
@forward 'display';

// Configuration through index
// config/_index.scss
@forward 'variables' with (
  $primary: #007bff !default,
  $spacing: 8px !default
);
@forward 'functions';
@forward 'mixins';

// main.scss
@use 'config' with (
  $primary: #ff0000  // Override default
);

// Multi-level barrel
scss/
├── core/
│   ├── _index.scss
│   ├── abstracts/
│   │   ├── _index.scss
│   │   ├── _variables.scss
│   │   └── _mixins.scss
│   └── base/
│       ├── _index.scss
│       └── _reset.scss
└── main.scss

// core/abstracts/_index.scss
@forward 'variables';
@forward 'mixins';

// core/base/_index.scss
@forward 'reset';

// core/_index.scss
@forward 'abstracts';
@forward 'base';

// main.scss
@use 'core';  // Everything in one import!

12.5 Dynamic Imports and Conditional Loading

Pattern Use Case Example Benefit
@if import Environment-based Dev vs production Conditional loading
Feature flags Toggle features A/B testing Flexible builds
Theme selection Multi-theme apps Dark/light modes Single build
Loop imports Similar files Icon sets, colors DRY imports

Example: Conditional and dynamic imports

// Environment-based imports
$env: 'production' !default;

@if $env == 'development' {
  @use 'dev/debug-grid';
  @use 'dev/component-outline';
  @use 'dev/performance-overlay';
} @else if $env == 'production' {
  @use 'prod/optimized-styles';
}

// Feature flags
$features: (
  animations: true,
  dark-mode: true,
  experimental-grid: false
);

@use 'sass:map';

@if map.get($features, animations) {
  @use 'animations/transitions';
  @use 'animations/keyframes';
}

@if map.get($features, dark-mode) {
  @use 'themes/dark';
}

@if map.get($features, experimental-grid) {
  @use 'experimental/subgrid';
}

// Dynamic theme loading
$active-theme: 'dark' !default;

// Only load the active theme
@if $active-theme == 'dark' {
  @use 'themes/dark';
} @else if $active-theme == 'light' {
  @use 'themes/light';
} @else if $active-theme == 'high-contrast' {
  @use 'themes/high-contrast';
} @else {
  @use 'themes/default';
}

// Browser-specific imports
$target-browser: 'modern' !default;

@if $target-browser == 'legacy' {
  @use 'vendors/normalize';
  @use 'polyfills/flexbox';
  @use 'polyfills/grid';
} @else {
  @use 'modern/reset';
}

// Responsive strategy selection
$responsive-strategy: 'mobile-first' !default;

@if $responsive-strategy == 'mobile-first' {
  @use 'responsive/mobile-first';
} @else if $responsive-strategy == 'desktop-first' {
  @use 'responsive/desktop-first';
} @else {
  @use 'responsive/adaptive';
}

// Import based on configuration
$enable-rtl: false !default;
$enable-print: true !default;

@if $enable-rtl {
  @use 'i18n/rtl';
}

@if $enable-print {
  @use 'print/styles';
}

// Loop-based imports (components)
$component-list: (
  'button',
  'card',
  'modal',
  'dropdown',
  'table'
);

@each $component in $component-list {
  @use 'components/#{$component}';
}

// Conditional utility imports
$utilities: (
  spacing: true,
  text: true,
  colors: false,
  display: true
);

@each $util, $enabled in $utilities {
  @if $enabled {
    @use 'utilities/#{$util}';
  }
}

// Breakpoint-based imports
$breakpoints: (
  sm: 576px,
  md: 768px,
  lg: 992px
);

$active-breakpoints: (sm, md, lg);

@each $bp in $active-breakpoints {
  @use 'responsive/#{$bp}';
}

// Platform-specific imports
$platform: 'web' !default;  // 'web', 'mobile', 'desktop'

@if $platform == 'mobile' {
  @use 'platforms/mobile/touch-optimized';
  @use 'platforms/mobile/gestures';
} @else if $platform == 'desktop' {
  @use 'platforms/desktop/hover-states';
  @use 'platforms/desktop/keyboard-nav';
} @else {
  @use 'platforms/web/standard';
}

// Conditional vendor imports
$include-vendors: (
  normalize: true,
  bootstrap-grid: false,
  animate-css: true
);

@if map.get($include-vendors, normalize) {
  @use 'vendors/normalize';
}

@if map.get($include-vendors, bootstrap-grid) {
  @use 'vendors/bootstrap-grid';
}

@if map.get($include-vendors, animate-css) {
  @use 'vendors/animate';
}

// Build configuration
$build-config: (
  minify: true,
  sourcemaps: true,
  rtl: false,
  themes: (dark, light),
  components: (button, card, modal)
);

// Load themes
@each $theme in map.get($build-config, themes) {
  @use 'themes/#{$theme}';
}

// Load components
@each $component in map.get($build-config, components) {
  @use 'components/#{$component}';
}

12.6 Glob Patterns and Bulk Imports

Tool Pattern Example Limitation
sass-loader Webpack glob @import '**/*.scss' Build tool required
node-sass includePaths Config option Node.js only
Dart Sass No native glob Manual imports Must use index files
gulp-sass Task runner glob src/**/*.scss External tool

Example: Bulk import strategies

// Note: Sass doesn't support native glob imports
// Must use build tools or index files

// Webpack sass-loader with glob (NOT standard Sass)
// webpack.config.js
module.exports = {
  module: {
    rules: [{
      test: /\.scss$/,
      use: ['style-loader', 'css-loader', 'sass-loader']
    }]
  }
};

// Then in SCSS (with plugins):
// @import 'components/**/*.scss';  // Not standard!

// STANDARD approach: Use index files
// components/_index.scss
@forward 'button';
@forward 'card';
@forward 'modal';
@forward 'dropdown';
// ... etc

// Or generate index programmatically (build script)
// generate-index.js
const fs = require('fs');
const path = require('path');

const componentsDir = './scss/components';
const files = fs.readdirSync(componentsDir)
  .filter(f => f.endsWith('.scss') && !f.startsWith('_index'))
  .map(f => f.replace('.scss', ''));

const indexContent = files
  .map(f => `@forward '${f}';`)
  .join('\n');

fs.writeFileSync(
  path.join(componentsDir, '_index.scss'),
  indexContent
);

// Gulp task for automatic index generation
// gulpfile.js
const gulp = require('gulp');
const concat = require('gulp-concat');

gulp.task('generate-imports', () => {
  return gulp.src('scss/components/_*.scss')
    .pipe(/* generate @forward statements */)
    .pipe(concat('_index.scss'))
    .pipe(gulp.dest('scss/components/'));
});

// Manual bulk import pattern (repetitive but clear)
// components/_index.scss
@forward 'button';
@forward 'button-group';
@forward 'button-toolbar';
@forward 'card';
@forward 'card-header';
@forward 'card-body';
@forward 'card-footer';
@forward 'modal';
@forward 'modal-dialog';
@forward 'dropdown';
@forward 'dropdown-menu';
@forward 'tooltip';
@forward 'popover';

// Alternative: Programmatic import helper
// _import-helper.scss
@use 'sass:meta';
@use 'sass:list';

@mixin import-all($folder, $files...) {
  @each $file in $files {
    // This doesn't actually work in Sass
    // Just showing the concept
    // @use '#{$folder}/#{$file}';
  }
}

// Vite glob imports (JavaScript side)
// main.ts
const modules = import.meta.glob('./styles/**/*.scss');

// Parcel glob (automatic)
// Just import the folder
@use 'components';  // Parcel handles the rest

// Best practice: Organized manual imports
// _all.scss (common pattern)
// Base
@forward 'base/reset';
@forward 'base/typography';
@forward 'base/forms';

// Layout
@forward 'layout/grid';
@forward 'layout/container';
@forward 'layout/header';
@forward 'layout/footer';

// Components (alphabetical for easy maintenance)
@forward 'components/alert';
@forward 'components/badge';
@forward 'components/breadcrumb';
@forward 'components/button';
@forward 'components/card';
@forward 'components/carousel';
@forward 'components/dropdown';
@forward 'components/modal';
@forward 'components/navbar';
@forward 'components/pagination';
@forward 'components/progress';
@forward 'components/spinner';
@forward 'components/table';
@forward 'components/tabs';
@forward 'components/tooltip';

// Node script to generate imports
// scripts/generate-sass-index.mjs
import { readdirSync, writeFileSync } from 'fs';
import { join, basename } from 'path';

function generateIndex(dir) {
  const files = readdirSync(dir)
    .filter(f => f.endsWith('.scss') && f !== '_index.scss')
    .map(f => basename(f, '.scss'))
    .filter(f => !f.startsWith('_index'));
  
  const imports = files
    .map(f => `@forward '${f}';`)
    .join('\n');
  
  writeFileSync(
    join(dir, '_index.scss'),
    `// Auto-generated - do not edit\n${imports}\n`
  );
}

generateIndex('./scss/components');
generateIndex('./scss/utilities');

// Package.json script
{
  "scripts": {
    "sass:index": "node scripts/generate-sass-index.mjs",
    "sass:build": "npm run sass:index && sass src/main.scss dist/styles.css"
  }
}

File Organization Summary

  • Partials: Use _filename.scss for files that shouldn't compile standalone
  • Import order: Config → Utils → Base → Layout → Components → Pages → Themes → Utilities
  • 7-1 Pattern: 7 folders + 1 main file for large projects
  • Index files: Use _index.scss with @forward for barrel exports
  • Conditional: Use @if for environment/feature-based imports
  • No glob: Sass has no native glob; use index files or build scripts
  • Modern approach: @use and @forward over deprecated @import
Warning: @import is deprecated. Use @use for importing and @forward for re-exporting. Migration is essential for Dart Sass 2.0.

13. Responsive Design and Media Query Management

13.1 Breakpoint Maps and Responsive Mixins

Component Pattern Description Example
Breakpoint map $breakpoints: (sm: 576px...) Named breakpoint values Centralized configuration
above() mixin @include above(md) Min-width media query Mobile-first
below() mixin @include below(lg) Max-width media query Desktop-first
between() mixin @include between(sm, lg) Range media query Specific ranges
only() mixin @include only(md) Exact breakpoint only Specific size
Custom queries Orientation, hover, etc. Feature detection Enhanced UX

Example: Comprehensive breakpoint system

@use 'sass:map';

// Breakpoint configuration
$breakpoints: (
  xs: 0,
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px,
  xxl: 1400px
) !default;

// Mobile-first: min-width
@mixin above($breakpoint) {
  $value: map.get($breakpoints, $breakpoint);
  
  @if $value {
    @if $value == 0 {
      @content;
    } @else {
      @media (min-width: $value) {
        @content;
      }
    }
  } @else {
    @error "Breakpoint '#{$breakpoint}' not found in $breakpoints map";
  }
}

// Desktop-first: max-width
@mixin below($breakpoint) {
  $value: map.get($breakpoints, $breakpoint);
  
  @if $value {
    @media (max-width: $value - 1px) {
      @content;
    }
  } @else {
    @error "Breakpoint '#{$breakpoint}' not found";
  }
}

// Between two breakpoints
@mixin between($min, $max) {
  $min-val: map.get($breakpoints, $min);
  $max-val: map.get($breakpoints, $max);
  
  @media (min-width: $min-val) and (max-width: $max-val - 1px) {
    @content;
  }
}

// Only at specific breakpoint
@mixin only($breakpoint) {
  $index: list.index(map.keys($breakpoints), $breakpoint);
  
  @if $index {
    $next-bp: list.nth(map.keys($breakpoints), $index + 1);
    @include between($breakpoint, $next-bp) {
      @content;
    }
  }
}

// Usage examples
.container {
  width: 100%;
  padding: 1rem;
  
  // Mobile-first progression
  @include above(sm) {
    max-width: 540px;
    margin: 0 auto;
  }
  
  @include above(md) {
    max-width: 720px;
    padding: 1.5rem;
  }
  
  @include above(lg) {
    max-width: 960px;
    padding: 2rem;
  }
  
  @include above(xl) {
    max-width: 1140px;
  }
  
  @include above(xxl) {
    max-width: 1320px;
  }
}

// Desktop-first approach
.sidebar {
  width: 100%;
  
  @include below(lg) {
    display: none;
  }
  
  @include above(lg) {
    width: 250px;
    position: fixed;
  }
}

// Between breakpoints
.promo-banner {
  display: none;
  
  // Only show between md and lg
  @include between(md, lg) {
    display: block;
    padding: 2rem;
  }
}

// Only at specific size
.tablet-specific {
  @include only(md) {
    // Only applies at md breakpoint
    columns: 2;
  }
}

// Advanced: Breakpoint helpers
@function breakpoint-min($name) {
  @return map.get($breakpoints, $name);
}

@function breakpoint-max($name) {
  $max: map.get($breakpoints, $name);
  @return if($max and $max > 0, $max - 1px, null);
}

@function breakpoint-infix($name) {
  @return if($name == xs, '', '-#{$name}');
}

// Generate responsive utilities
$utilities: (
  display: (none, block, flex, grid),
  text-align: (left, center, right)
);

@each $property, $values in $utilities {
  @each $value in $values {
    @each $bp-name, $bp-value in $breakpoints {
      $infix: breakpoint-infix($bp-name);
      
      .#{$property}#{$infix}-#{$value} {
        @include above($bp-name) {
          #{$property}: $value;
        }
      }
    }
  }
}
// Generates: .display-sm-block, .text-align-md-center, etc.

// Custom media query mixins
@mixin landscape {
  @media (orientation: landscape) {
    @content;
  }
}

@mixin portrait {
  @media (orientation: portrait) {
    @content;
  }
}

@mixin retina {
  @media (-webkit-min-device-pixel-ratio: 2),
         (min-resolution: 192dpi) {
    @content;
  }
}

@mixin hover-supported {
  @media (hover: hover) and (pointer: fine) {
    &:hover {
      @content;
    }
  }
}

@mixin touch-device {
  @media (hover: none) and (pointer: coarse) {
    @content;
  }
}

@mixin prefers-dark {
  @media (prefers-color-scheme: dark) {
    @content;
  }
}

@mixin prefers-light {
  @media (prefers-color-scheme: light) {
    @content;
  }
}

@mixin reduced-motion {
  @media (prefers-reduced-motion: reduce) {
    @content;
  }
}

// Usage
.image {
  width: 100%;
  
  @include retina {
    content: url('image@2x.png');
  }
}

.button {
  background: blue;
  
  @include hover-supported {
    background: darkblue;
  }
  
  @include touch-device {
    padding: 12px 24px; // Larger touch targets
  }
}

.theme {
  background: white;
  
  @include prefers-dark {
    background: #1a1a1a;
  }
}

.animated {
  transition: all 0.3s;
  
  @include reduced-motion {
    transition: none;
  }
}

13.2 Mobile-first vs Desktop-first Patterns

Approach Query Type Base Styles Best For
Mobile-first min-width Mobile base, enhance up Modern apps, performance
Desktop-first max-width Desktop base, reduce down Legacy sites, admin panels
Hybrid Both min/max Tablet base, both directions Complex layouts
Content-first As needed Break where content dictates Editorial sites

Example: Mobile-first vs Desktop-first comparison

// MOBILE-FIRST (Recommended)
// Start with mobile, enhance for larger screens
.card {
  // Base styles (mobile)
  width: 100%;
  padding: 1rem;
  margin-bottom: 1rem;
  
  // Enhance for tablet
  @include above(md) {
    width: 48%;
    float: left;
    margin-right: 2%;
  }
  
  // Enhance for desktop
  @include above(lg) {
    width: 31.333%;
    margin-right: 2%;
  }
  
  // Enhance for large desktop
  @include above(xl) {
    width: 23%;
    margin-right: 1.5%;
  }
}

// DESKTOP-FIRST
// Start with desktop, reduce for smaller screens
.sidebar {
  // Base styles (desktop)
  width: 300px;
  float: left;
  padding: 2rem;
  
  // Reduce for laptop
  @include below(xl) {
    width: 250px;
    padding: 1.5rem;
  }
  
  // Reduce for tablet
  @include below(lg) {
    width: 200px;
    padding: 1rem;
  }
  
  // Stack on mobile
  @include below(md) {
    width: 100%;
    float: none;
  }
}

// MOBILE-FIRST: Typography
.heading {
  // Mobile base
  font-size: 1.5rem;
  line-height: 1.3;
  margin-bottom: 1rem;
  
  @include above(md) {
    font-size: 2rem;
    line-height: 1.2;
  }
  
  @include above(lg) {
    font-size: 2.5rem;
  }
  
  @include above(xl) {
    font-size: 3rem;
    line-height: 1.1;
  }
}

// DESKTOP-FIRST: Navigation
.nav {
  // Desktop base
  display: flex;
  gap: 2rem;
  
  @include below(md) {
    flex-direction: column;
    gap: 0;
  }
  
  &__item {
    // Desktop
    padding: 0.5rem 1rem;
    
    @include below(md) {
      padding: 1rem;
      border-bottom: 1px solid #ddd;
    }
  }
}

// HYBRID: Best of both
.product-grid {
  display: grid;
  gap: 1rem;
  
  // Mobile base (1 column)
  grid-template-columns: 1fr;
  
  // Tablet (2 columns) - mobile-first
  @include above(sm) {
    grid-template-columns: repeat(2, 1fr);
  }
  
  // Small desktop (3 columns) - mobile-first
  @include above(md) {
    grid-template-columns: repeat(3, 1fr);
    gap: 1.5rem;
  }
  
  // Large desktop (4 columns) - mobile-first
  @include above(lg) {
    grid-template-columns: repeat(4, 1fr);
    gap: 2rem;
  }
  
  // But hide on very small screens - desktop-first concept
  @include below(xs) {
    display: none; // Too small to be useful
  }
}

// CONTENT-FIRST: Break where content needs it
.article {
  font-size: 16px;
  line-height: 1.6;
  max-width: 100%;
  
  // When line length gets too long
  @media (min-width: 600px) {
    max-width: 600px;
    margin: 0 auto;
  }
  
  // Add columns when there's room
  @media (min-width: 900px) {
    columns: 2;
    column-gap: 3rem;
  }
}

// Mobile-first: Progressive enhancement
.feature {
  // Simple mobile version
  background: white;
  padding: 1rem;
  
  @include above(md) {
    // Add complexity on larger screens
    display: grid;
    grid-template-columns: 1fr 2fr;
    gap: 2rem;
  }
  
  @include above(lg) {
    // Add more features
    box-shadow: 0 4px 8px rgba(0,0,0,0.1);
    border-radius: 8px;
  }
  
  @supports (backdrop-filter: blur(10px)) {
    @include above(lg) {
      // Modern feature for capable browsers
      backdrop-filter: blur(10px);
      background: rgba(255,255,255,0.9);
    }
  }
}

// Desktop-first: Graceful degradation
.dashboard {
  // Complex desktop layout
  display: grid;
  grid-template-columns: 250px 1fr 300px;
  grid-template-areas: "sidebar main widgets";
  gap: 2rem;
  
  @include below(lg) {
    // Simplify for tablet
    grid-template-columns: 200px 1fr;
    grid-template-areas: "sidebar main";
    
    .widgets {
      display: none;
    }
  }
  
  @include below(md) {
    // Stack for mobile
    grid-template-columns: 1fr;
    grid-template-areas: "main";
    
    .sidebar {
      display: none;
    }
  }
}

// Performance consideration (mobile-first wins)
.heavy-feature {
  // Simple mobile version (fast)
  display: block;
  
  @include above(lg) {
    // Complex desktop version (more resources available)
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 2rem;
    
    &::before,
    &::after {
      // Decorative elements only on desktop
      content: '';
      // ... complex styles
    }
  }
}

13.3 Container Query Integration

Property Syntax Description Use Case
container-type inline-size | size Define container Enable queries
container-name container-name: sidebar Named containers Target specific
@container @container (min-width) Container query Component responsive
Container units cqw, cqh, cqi, cqb Container-relative units Fluid sizing

Example: Modern container queries

// Container query mixin
@mixin container($min-width) {
  @container (min-width: $min-width) {
    @content;
  }
}

@mixin container-named($name, $min-width) {
  @container #{$name} (min-width: $min-width) {
    @content;
  }
}

// Define container
.card-container {
  container-type: inline-size;
  container-name: card;
}

// Child responds to container size, not viewport
.card {
  padding: 1rem;
  
  // When container is 400px+
  @container (min-width: 400px) {
    display: grid;
    grid-template-columns: 150px 1fr;
    gap: 1rem;
  }
  
  // When container is 600px+
  @container (min-width: 600px) {
    grid-template-columns: 200px 1fr 150px;
    padding: 2rem;
  }
  
  &__title {
    font-size: 1rem;
    
    @container (min-width: 400px) {
      font-size: 1.25rem;
    }
    
    @container (min-width: 600px) {
      font-size: 1.5rem;
    }
  }
}

// Named container queries
.sidebar {
  container-type: inline-size;
  container-name: sidebar;
  
  .widget {
    // Responds to sidebar size
    @container sidebar (min-width: 300px) {
      display: grid;
      grid-template-columns: 1fr 1fr;
    }
  }
}

// Container query with mixin
.component-wrapper {
  container-type: inline-size;
  
  .component {
    display: block;
    
    @include container(500px) {
      display: flex;
      gap: 1rem;
    }
    
    @include container(700px) {
      gap: 2rem;
      padding: 2rem;
    }
  }
}

// Responsive component that works anywhere
.product-card {
  // No media queries needed!
  // Responds to its container
  
  &-container {
    container-type: inline-size;
  }
  
  display: block;
  
  // Small container
  @container (min-width: 250px) {
    &__image {
      aspect-ratio: 16/9;
    }
  }
  
  // Medium container
  @container (min-width: 400px) {
    display: grid;
    grid-template-columns: 40% 1fr;
    
    &__image {
      aspect-ratio: 1;
    }
  }
  
  // Large container
  @container (min-width: 600px) {
    grid-template-columns: 200px 1fr;
    gap: 2rem;
    
    &__title {
      font-size: 1.5rem;
    }
  }
}

// Container query units
.fluid-component {
  container-type: inline-size;
  
  &__heading {
    // Font size relative to container width
    font-size: calc(1rem + 2cqw);
    
    // Padding relative to container
    padding: 1cqi; // inline
  }
  
  &__content {
    // Gap relative to container
    gap: 2cqw;
  }
}

// Fallback for no container query support
.card {
  padding: 1rem;
  
  // Traditional media query fallback
  @media (min-width: 768px) {
    @supports not (container-type: inline-size) {
      display: grid;
      grid-template-columns: 1fr 2fr;
    }
  }
  
  // Modern container query
  @supports (container-type: inline-size) {
    @container (min-width: 400px) {
      display: grid;
      grid-template-columns: 1fr 2fr;
    }
  }
}

// Practical: Responsive card system
.card-grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  
  .card {
    // Each card is a container
    container-type: inline-size;
    
    &__layout {
      // Adapts to card size, not viewport
      @container (max-width: 350px) {
        // Narrow card: stack
        display: flex;
        flex-direction: column;
      }
      
      @container (min-width: 351px) and (max-width: 500px) {
        // Medium card: side-by-side
        display: grid;
        grid-template-columns: 100px 1fr;
      }
      
      @container (min-width: 501px) {
        // Wide card: complex layout
        display: grid;
        grid-template-columns: 150px 1fr 100px;
      }
    }
  }
}

// Container queries with style queries (future)
.theme-container {
  container-type: inline-size;
  
  // Style query (experimental)
  // @container style(--theme: dark) {
  //   background: #1a1a1a;
  // }
}

13.4 Responsive Typography with Fluid Scaling

Technique Formula Description Browser Support
clamp() clamp(min, preferred, max) CSS clamp function Modern browsers
Fluid calc() calc(min + slope * vw) Linear interpolation All browsers
vw units font-size: 2.5vw Viewport width Simple but no limits
Modular scale base * ratio^n Proportional sizing Mathematical harmony

Example: Fluid responsive typography

@use 'sass:math';

// Modern approach: clamp()
.heading {
  // min: 1.5rem, preferred: 5vw, max: 3rem
  font-size: clamp(1.5rem, 5vw, 3rem);
  
  // Line height also fluid
  line-height: clamp(1.2, 1.5vw, 1.5);
}

// Fluid typography function
@function fluid-size($min, $max, $min-vw: 320px, $max-vw: 1200px) {
  $min-val: math.div($min, 1px);
  $max-val: math.div($max, 1px);
  $min-vw-val: math.div($min-vw, 1px);
  $max-vw-val: math.div($max-vw, 1px);
  
  $slope: math.div($max-val - $min-val, $max-vw-val - $min-vw-val);
  $intercept: $min-val - $slope * $min-vw-val;
  
  @return clamp(
    #{$min},
    #{$intercept}px + #{$slope * 100}vw,
    #{$max}
  );
}

// Usage
h1 {
  font-size: fluid-size(24px, 48px);  // 24px to 48px
}

h2 {
  font-size: fluid-size(20px, 36px);
}

p {
  font-size: fluid-size(16px, 18px);
}

// Fluid spacing
@function fluid-space($min, $max) {
  @return fluid-size($min, $max, 320px, 1200px);
}

.container {
  padding: fluid-space(16px, 48px);
  gap: fluid-space(1rem, 3rem);
}

// Modular scale with fluid base
@function modular-scale($level, $base: 16px, $ratio: 1.25) {
  @return $base * math.pow($ratio, $level);
}

// Fluid modular scale
$base-font-size: fluid-size(16px, 20px);

h1 { font-size: modular-scale(4, $base-font-size); }
h2 { font-size: modular-scale(3, $base-font-size); }
h3 { font-size: modular-scale(2, $base-font-size); }
h4 { font-size: modular-scale(1, $base-font-size); }
p  { font-size: $base-font-size; }

// Responsive type scale map
$type-scale: (
  xs: (
    h1: 1.75rem,
    h2: 1.5rem,
    h3: 1.25rem,
    p: 1rem
  ),
  md: (
    h1: 2.5rem,
    h2: 2rem,
    h3: 1.5rem,
    p: 1.125rem
  ),
  xl: (
    h1: 3.5rem,
    h2: 2.75rem,
    h3: 2rem,
    p: 1.25rem
  )
);

@mixin responsive-typography {
  @each $element, $size in map.get($type-scale, xs) {
    #{$element} {
      font-size: $size;
    }
  }
  
  @include above(md) {
    @each $element, $size in map.get($type-scale, md) {
      #{$element} {
        font-size: $size;
      }
    }
  }
  
  @include above(xl) {
    @each $element, $size in map.get($type-scale, xl) {
      #{$element} {
        font-size: $size;
      }
    }
  }
}

// Apply to scope
.article {
  @include responsive-typography;
}

// Viewport-based with constraints
.hero-title {
  font-size: calc(1.5rem + 2vw);
  
  // But add safety constraints
  @media (max-width: 320px) {
    font-size: 1.5rem; // Minimum
  }
  
  @media (min-width: 1920px) {
    font-size: 4rem; // Maximum
  }
}

// Fluid line height
@function fluid-line-height($min, $max) {
  @return clamp($min, calc(#{$min} + (#{$max} - #{$min}) * 0.5vw), $max);
}

.text {
  line-height: fluid-line-height(1.4, 1.8);
}

// Container query typography
.card {
  container-type: inline-size;
  
  &__title {
    // Scales with container, not viewport
    font-size: clamp(1rem, 4cqi, 2rem);
  }
}

// Accessible fluid typography
@function accessible-fluid($min, $max) {
  // Ensure minimum readable size
  $safe-min: math.max($min, 16px);
  @return fluid-size($safe-min, $max);
}

// Practical: Complete typography system
$fluid-typography: (
  display: fluid-size(48px, 96px),
  h1: fluid-size(32px, 48px),
  h2: fluid-size(24px, 36px),
  h3: fluid-size(20px, 28px),
  h4: fluid-size(18px, 24px),
  h5: fluid-size(16px, 20px),
  h6: fluid-size(14px, 18px),
  body: fluid-size(16px, 18px),
  small: fluid-size(14px, 16px)
);

@each $element, $size in $fluid-typography {
  .#{$element} {
    font-size: $size;
  }
}

// Optical sizing (variable fonts)
.variable-font {
  font-size: clamp(1rem, 2vw, 2rem);
  font-variation-settings: 
    'opsz' calc(16 + (32 - 16) * ((100vw - 320px) / (1920 - 320)));

13.5 Responsive Grid Systems and Layout Mixins

System Approach Example Best For
Fixed columns 12-column grid Bootstrap-style Traditional layouts
Fluid grid Percentage-based Flexible columns Responsive layouts
CSS Grid Native grid grid-template-columns Modern layouts
Flexbox Flexible box flex-basis, flex-grow 1D layouts
Auto-fit Responsive grid repeat(auto-fit, minmax()) Card grids

Example: Responsive grid systems

// 12-column responsive grid system
$grid-columns: 12;
$grid-gutter: 30px;

@mixin make-container {
  width: 100%;
  padding: 0 math.div($grid-gutter, 2);
  margin: 0 auto;
}

@mixin make-row {
  display: flex;
  flex-wrap: wrap;
  margin: 0 math.div($grid-gutter, -2);
}

@mixin make-col($size, $columns: $grid-columns) {
  flex: 0 0 auto;
  width: math.percentage(math.div($size, $columns));
  padding: 0 math.div($grid-gutter, 2);
}

// Usage
.container {
  @include make-container;
}

.row {
  @include make-row;
}

.col-6 {
  @include make-col(6);  // 50%
}

.col-4 {
  @include make-col(4);  // 33.333%
}

// Responsive columns
@mixin make-col-responsive($sizes) {
  @each $bp, $size in $sizes {
    @include above($bp) {
      @include make-col($size);
    }
  }
}

.col-responsive {
  @include make-col-responsive((
    xs: 12,  // Full width mobile
    md: 6,   // Half width tablet
    lg: 4,   // Third width desktop
    xl: 3    // Quarter width large
  ));
}

// Modern CSS Grid system
@mixin grid-columns($mobile: 1, $tablet: 2, $desktop: 3, $wide: 4) {
  display: grid;
  gap: $grid-gutter;
  grid-template-columns: repeat($mobile, 1fr);
  
  @include above(md) {
    grid-template-columns: repeat($tablet, 1fr);
  }
  
  @include above(lg) {
    grid-template-columns: repeat($desktop, 1fr);
  }
  
  @include above(xl) {
    grid-template-columns: repeat($wide, 1fr);
  }
}

.product-grid {
  @include grid-columns(1, 2, 3, 4);
}

// Auto-responsive grid (no media queries!)
.auto-grid {
  display: grid;
  gap: 1rem;
  
  // Automatically responsive
  grid-template-columns: repeat(
    auto-fit,
    minmax(min(300px, 100%), 1fr)
  );
}

// Responsive grid areas
.layout {
  display: grid;
  gap: 1rem;
  
  // Mobile: stacked
  grid-template-areas:
    "header"
    "main"
    "sidebar"
    "footer";
  
  @include above(md) {
    // Tablet: sidebar alongside
    grid-template-columns: 200px 1fr;
    grid-template-areas:
      "header header"
      "sidebar main"
      "footer footer";
  }
  
  @include above(lg) {
    // Desktop: 3-column
    grid-template-columns: 200px 1fr 250px;
    grid-template-areas:
      "header header header"
      "sidebar main widgets"
      "footer footer footer";
  }
}

.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.widgets { grid-area: widgets; }
.footer { grid-area: footer; }

// Flexbox responsive layout
@mixin flex-layout($gap: 1rem) {
  display: flex;
  flex-wrap: wrap;
  gap: $gap;
  
  & > * {
    // Mobile: full width
    flex: 1 1 100%;
    
    @include above(md) {
      // Tablet: half width
      flex: 1 1 calc(50% - #{$gap});
    }
    
    @include above(lg) {
      // Desktop: third width
      flex: 1 1 calc(33.333% - #{$gap});
    }
  }
}

.flex-container {
  @include flex-layout(2rem);
}

// Utility: Responsive columns
@for $i from 1 through 12 {
  @each $bp-name, $bp-value in $breakpoints {
    $infix: if($bp-name == xs, '', '-#{$bp-name}');
    
    .col#{$infix}-#{$i} {
      @include above($bp-name) {
        @include make-col($i);
      }
    }
  }
}
// Generates: .col-1, .col-md-6, .col-lg-4, etc.

// Responsive gap
@mixin responsive-gap($mobile, $tablet, $desktop) {
  gap: $mobile;
  
  @include above(md) {
    gap: $tablet;
  }
  
  @include above(lg) {
    gap: $desktop;
  }
}

.grid {
  @include responsive-gap(1rem, 1.5rem, 2rem);
}

// Holy Grail Layout (responsive)
.holy-grail {
  display: grid;
  min-height: 100vh;
  
  // Mobile: stacked
  grid-template:
    "header" auto
    "main" 1fr
    "left" auto
    "right" auto
    "footer" auto / 1fr;
  
  @include above(lg) {
    // Desktop: classic 3-column
    grid-template:
      "header header header" auto
      "left main right" 1fr
      "footer footer footer" auto
      / 200px 1fr 200px;
  }
}

13.6 Print Media and Alternative Media Types

Media Type Query Purpose Common Adjustments
print @media print Printing Hide nav, show URLs
screen @media screen Digital displays Default styles
speech @media speech Screen readers Accessibility
all @media all All devices Universal styles

Example: Print styles and alternative media

// Print styles mixin
@mixin print-styles {
  @media print {
    @content;
  }
}

// Global print optimizations
@media print {
  * {
    background: transparent !important;
    color: black !important;
    box-shadow: none !important;
    text-shadow: none !important;
  }
  
  // Page setup
  @page {
    margin: 2cm;
    size: A4 portrait;
  }
  
  // Typography
  body {
    font-size: 12pt;
    line-height: 1.5;
  }
  
  h1 { font-size: 24pt; }
  h2 { font-size: 18pt; }
  h3 { font-size: 14pt; }
  
  // Links
  a {
    text-decoration: underline;
    color: black;
    
    // Show URL after link
    &[href]::after {
      content: " (" attr(href) ")";
      font-size: 10pt;
    }
    
    // Don't show for anchors
    &[href^="#"]::after,
    &[href^="javascript:"]::after {
      content: "";
    }
  }
  
  // Images
  img {
    max-width: 100%;
    page-break-inside: avoid;
  }
  
  // Tables
  table {
    border-collapse: collapse;
    
    th, td {
      border: 1px solid #ddd;
      padding: 8pt;
    }
  }
  
  // Page breaks
  h1, h2, h3, h4, h5, h6 {
    page-break-after: avoid;
    page-break-inside: avoid;
  }
  
  p, blockquote {
    page-break-inside: avoid;
  }
  
  thead {
    display: table-header-group;
  }
  
  tr, img {
    page-break-inside: avoid;
  }
  
  // Hide non-printable elements
  nav,
  .no-print,
  .sidebar,
  .advertisement,
  button,
  video,
  audio {
    display: none !important;
  }
  
  // Show hidden content
  .print-only {
    display: block !important;
  }
}

// Component-specific print styles
.article {
  // Screen styles
  max-width: 800px;
  margin: 0 auto;
  
  @include print-styles {
    // Print styles
    max-width: 100%;
    margin: 0;
    
    &__header {
      border-bottom: 2pt solid black;
      padding-bottom: 1rem;
    }
    
    &__footer {
      border-top: 1pt solid #ccc;
      margin-top: 2rem;
      padding-top: 1rem;
    }
  }
}

// QR code for print
.share-link {
  display: inline-block;
  
  @media print {
    &::after {
      content: "";
      display: block;
      width: 100px;
      height: 100px;
      background: url('/qr-code.png');
      background-size: contain;
    }
  }
}

// Print-specific utilities
.page-break-before {
  @media print {
    page-break-before: always;
  }
}

.page-break-after {
  @media print {
    page-break-after: always;
  }
}

.avoid-break {
  @media print {
    page-break-inside: avoid;
  }
}

// @page rules for different sections
@media print {
  @page :first {
    margin-top: 5cm;
  }
  
  @page :left {
    margin-left: 3cm;
    margin-right: 2cm;
  }
  
  @page :right {
    margin-left: 2cm;
    margin-right: 3cm;
  }
  
  // Named pages
  @page chapter {
    margin: 3cm;
    
    @top-center {
      content: "Chapter " counter(chapter);
    }
  }
}

.chapter {
  @media print {
    page: chapter;
  }
}

// Screen reader / speech styles
@media speech {
  // Control speech rate
  .fast-read {
    voice-rate: fast;
  }
  
  .slow-read {
    voice-rate: slow;
  }
  
  // Pause before headings
  h1, h2, h3 {
    pause-before: 300ms;
    pause-after: 200ms;
  }
  
  // Spell out abbreviations
  abbr {
    speak: spell-out;
  }
}

// Projection media (presentations)
@media projection {
  body {
    font-size: 24pt;
  }
  
  .slide {
    page-break-after: always;
    min-height: 100vh;
  }
}

// High contrast mode
@media (prefers-contrast: high) {
  .card {
    border: 2px solid currentColor;
    background: white;
    color: black;
  }
}

// Inverted colors
@media (inverted-colors: inverted) {
  img, video {
    filter: invert(1);
  }
}

Responsive Design Summary

  • Breakpoints: Use map-based system with above(), below(), between() mixins
  • Mobile-first: Preferred approach using min-width queries (progressive enhancement)
  • Container queries: Component-level responsive design with @container
  • Fluid typography: Use clamp() or fluid-size() for scalable text
  • Grid systems: CSS Grid with auto-fit for truly responsive layouts
  • Print media: Hide nav, show URLs, optimize for paper
  • Modern features: Container queries, clamp(), prefers-* media features
Note: Container queries provide component-level responsiveness, making components truly reusable across different contexts without media queries.

14. Color Management and Theme Systems

14.1 Color Palette Maps and Theme Variables

Pattern Syntax Description Use Case
Color Maps $colors: (key: value) Organize colors in map structure Brand color systems
Nested Palettes $theme: (primary: (light: ..., dark: ...)) Multi-level color organization Color variants
Semantic Naming $color-primary, $color-success Purpose-based naming Maintainable themes
Shade Generation @function shade($color, $level) Auto-generate color variants Consistent palettes
Color Tokens $token-color-primary-500 Design token convention Design system integration

Example: Comprehensive color palette system

// Base color palette
$colors: (
  primary: #1976d2,
  secondary: #dc004e,
  success: #4caf50,
  warning: #ff9800,
  error: #f44336,
  info: #2196f3,
  neutral: #9e9e9e
);

// Generate shade levels (50-900)
@function generate-shades($base-color) {
  @return (
    50: mix(white, $base-color, 90%),
    100: mix(white, $base-color, 80%),
    200: mix(white, $base-color, 60%),
    300: mix(white, $base-color, 40%),
    400: mix(white, $base-color, 20%),
    500: $base-color,
    600: mix(black, $base-color, 20%),
    700: mix(black, $base-color, 40%),
    800: mix(black, $base-color, 60%),
    900: mix(black, $base-color, 80%)
  );
}

// Complete theme with all shades
$theme-colors: ();
@each $name, $color in $colors {
  $theme-colors: map-merge($theme-colors, (
    $name: generate-shades($color)
  ));
}

// Access function
@function theme-color($color, $shade: 500) {
  @return map-get(map-get($theme-colors, $color), $shade);
}

// Usage
.button-primary {
  background: theme-color(primary);
  &:hover { background: theme-color(primary, 600); }
  &:active { background: theme-color(primary, 700); }
}

// Semantic color variables
$color-background: theme-color(neutral, 50);
$color-surface: white;
$color-text-primary: rgba(0, 0, 0, 0.87);
$color-text-secondary: rgba(0, 0, 0, 0.60);
$color-divider: rgba(0, 0, 0, 0.12);

Example: Advanced nested theme structure

// Multi-theme system
$themes: (
  light: (
    background: (
      primary: #ffffff,
      secondary: #f5f5f5,
      elevated: #fafafa
    ),
    text: (
      primary: rgba(0, 0, 0, 0.87),
      secondary: rgba(0, 0, 0, 0.60),
      disabled: rgba(0, 0, 0, 0.38)
    ),
    brand: (
      primary: #1976d2,
      secondary: #dc004e,
      accent: #ff9800
    )
  ),
  dark: (
    background: (
      primary: #121212,
      secondary: #1e1e1e,
      elevated: #2c2c2c
    ),
    text: (
      primary: rgba(255, 255, 255, 0.87),
      secondary: rgba(255, 255, 255, 0.60),
      disabled: rgba(255, 255, 255, 0.38)
    ),
    brand: (
      primary: #90caf9,
      secondary: #f48fb1,
      accent: #ffb74d
    )
  )
);

// Deep map getter
@function theme-get($theme, $category, $variant) {
  $theme-map: map-get($themes, $theme);
  $category-map: map-get($theme-map, $category);
  @return map-get($category-map, $variant);
}

14.2 Color Scheme Generation and Automation

Technique Implementation Description Output
Complementary adjust-hue($color, 180deg) Opposite on color wheel High contrast pairs
Analogous adjust-hue($color, ±30deg) Adjacent colors Harmonious schemes
Triadic adjust-hue($color, 120deg) Evenly spaced colors Vibrant palettes
Monochromatic lighten/darken($color, %) Single hue variations Cohesive design
Tint/Shade mix(white/black, $color, %) Add white/black Subtle variations
Tone mix(gray, $color, %) Add gray Muted colors

Example: Automatic color scheme generators

// Complementary scheme
@function complementary-scheme($base) {
  @return (
    base: $base,
    complement: adjust-hue($base, 180deg)
  );
}

// Analogous scheme
@function analogous-scheme($base, $angle: 30deg) {
  @return (
    base: $base,
    left: adjust-hue($base, -$angle),
    right: adjust-hue($base, $angle)
  );
}

// Triadic scheme
@function triadic-scheme($base) {
  @return (
    primary: $base,
    secondary: adjust-hue($base, 120deg),
    tertiary: adjust-hue($base, 240deg)
  );
}

// Split complementary
@function split-complementary($base, $angle: 150deg) {
  @return (
    base: $base,
    left: adjust-hue($base, $angle),
    right: adjust-hue($base, -$angle)
  );
}

// Monochromatic with tints and shades
@function monochromatic-scheme($base, $steps: 5) {
  $scheme: ();
  @for $i from 1 through $steps {
    $lighter: lighten($base, $i * 10%);
    $darker: darken($base, $i * 10%);
    $scheme: map-merge($scheme, (
      'light-#{$i}': $lighter,
      'dark-#{$i}': $darker
    ));
  }
  @return map-merge($scheme, (base: $base));
}

// Usage
$brand: #1976d2;
$palette: triadic-scheme($brand);

.primary { color: map-get($palette, primary); }
.secondary { color: map-get($palette, secondary); }
.tertiary { color: map-get($palette, tertiary); }

Example: Material Design-style palette generator

@use 'sass:color';
@use 'sass:map';

@function material-palette($base-color) {
  $palette: ();
  
  // Define lightness levels
  $levels: (
    50: 95%,
    100: 90%,
    200: 80%,
    300: 70%,
    400: 60%,
    500: 50%,  // base
    600: 40%,
    700: 30%,
    800: 20%,
    900: 10%
  );
  
  @each $level, $lightness in $levels {
    $adjusted: change-color($base-color, $lightness: $lightness);
    $palette: map.merge($palette, ($level: $adjusted));
  }
  
  // Add accent colors (A100-A700)
  $palette: map.merge($palette, (
    'A100': lighten(saturate($base-color, 20%), 20%),
    'A200': lighten(saturate($base-color, 20%), 10%),
    'A400': saturate($base-color, 20%),
    'A700': darken(saturate($base-color, 20%), 10%)
  ));
  
  @return $palette;
}

// Generate complete color system
$primary: material-palette(#1976d2);
$accent: material-palette(#ff4081);

.button {
  background: map.get($primary, 500);
  &:hover { background: map.get($primary, 600); }
  &.accent { background: map.get($accent, 'A200'); }
}

14.3 Dark Mode and Light Mode Implementation

Approach Method Pros Cons
CSS Variables Change custom properties Runtime switching, scoped Browser support
Separate Files Load different CSS Simple, cacheable Flash of wrong theme
Class Toggle .dark-mode class Full control CSS duplication
Media Query prefers-color-scheme Respects OS setting No manual override
Hybrid Media query + class Best of both More complex
// Define theme maps
$light-theme: (
  bg-primary: #ffffff,
  bg-secondary: #f5f5f5,
  text-primary: #212121,
  text-secondary: #757575,
  border: #e0e0e0,
  shadow: rgba(0, 0, 0, 0.1)
);

$dark-theme: (
  bg-primary: #121212,
  bg-secondary: #1e1e1e,
  text-primary: #ffffff,
  text-secondary: #b0b0b0,
  border: #333333,
  shadow: rgba(0, 0, 0, 0.5)
);

// Generate CSS variables mixin
@mixin theme-variables($theme) {
  @each $name, $value in $theme {
    --color-#{$name}: #{$value};
  }
}

// Apply themes
:root {
  @include theme-variables($light-theme);
  color-scheme: light;
}

[data-theme="dark"] {
  @include theme-variables($dark-theme);
  color-scheme: dark;
}

// Respect system preference
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    @include theme-variables($dark-theme);
    color-scheme: dark;
  }
}

// Usage in components
.card {
  background: var(--color-bg-primary);
  color: var(--color-text-primary);
  border: 1px solid var(--color-border);
  box-shadow: 0 2px 4px var(--color-shadow);
}

Example: SCSS mixin-based theme system

// Theme configuration
$themes: (
  light: (
    background: #ffffff,
    surface: #f5f5f5,
    primary: #1976d2,
    on-background: #000000,
    on-surface: #212121,
    on-primary: #ffffff
  ),
  dark: (
    background: #121212,
    surface: #1e1e1e,
    primary: #90caf9,
    on-background: #ffffff,
    on-surface: #e0e0e0,
    on-primary: #000000
  )
);

// Theme mixin
@mixin themed($property, $color-key) {
  @each $theme-name, $theme-colors in $themes {
    [data-theme="#{$theme-name}"] & {
      #{$property}: map-get($theme-colors, $color-key);
    }
  }
}

// Multi-property theme mixin
@mixin theme-colors($map) {
  @each $theme-name, $theme-colors in $themes {
    [data-theme="#{$theme-name}"] & {
      @each $property, $color-key in $map {
        #{$property}: map-get($theme-colors, $color-key);
      }
    }
  }
}

// Usage
.button {
  @include themed(background-color, primary);
  @include themed(color, on-primary);
  
  &:hover {
    @include themed(background-color, surface);
  }
}

.card {
  @include theme-colors((
    background-color: surface,
    color: on-surface,
    border-color: primary
  ));
}

Example: Advanced dark mode with elevation

// Dark mode elevation system
@function dark-elevation($level) {
  $opacity: 0.05 * $level;
  @return rgba(255, 255, 255, $opacity);
}

// Elevation mixin for dark mode
@mixin elevation($level: 1) {
  [data-theme="light"] & {
    box-shadow: 0 #{$level * 2}px #{$level * 4}px rgba(0, 0, 0, 0.1);
  }
  
  [data-theme="dark"] & {
    background: mix(white, #121212, $level * 5%);
    box-shadow: 0 #{$level * 2}px #{$level * 4}px rgba(0, 0, 0, 0.5);
  }
}

// Surface tint for Material Design 3
@mixin surface-tint($level: 1) {
  [data-theme="light"] & {
    background: white;
  }
  
  [data-theme="dark"] & {
    $tint: mix(#90caf9, #121212, $level * 5%);
    background: $tint;
  }
}

.card {
  @include elevation(2);
  
  &.elevated {
    @include elevation(8);
  }
  
  &.surface {
    @include surface-tint(3);
  }
}

14.4 Accessibility Color Contrast Functions

Function Purpose WCAG Level Ratio Required
contrast-ratio() Calculate contrast ratio - Returns number
is-accessible() Check WCAG compliance AA/AAA 4.5:1 / 7:1
accessible-color() Auto-adjust for contrast AA 4.5:1
text-color() Choose black/white text AA Based on background
Large Text 18pt+ or 14pt+ bold AA 3:1
UI Components Interactive elements AA 3:1

Example: Contrast ratio calculation and validation

@use 'sass:math';
@use 'sass:color';

// Calculate relative luminance
@function luminance($color) {
  $r: color.red($color) / 255;
  $g: color.green($color) / 255;
  $b: color.blue($color) / 255;
  
  $r: if($r <= 0.03928, $r / 12.92, math.pow(($r + 0.055) / 1.055, 2.4));
  $g: if($g <= 0.03928, $g / 12.92, math.pow(($g + 0.055) / 1.055, 2.4));
  $b: if($b <= 0.03928, $b / 12.92, math.pow(($b + 0.055) / 1.055, 2.4));
  
  @return 0.2126 * $r + 0.7152 * $g + 0.0722 * $b;
}

// Calculate contrast ratio
@function contrast-ratio($fg, $bg) {
  $l1: luminance($fg);
  $l2: luminance($bg);
  
  $lighter: math.max($l1, $l2);
  $darker: math.min($l1, $l2);
  
  @return math.div($lighter + 0.05, $darker + 0.05);
}

// Check WCAG compliance
@function is-accessible($fg, $bg, $level: 'AA', $size: 'normal') {
  $ratio: contrast-ratio($fg, $bg);
  
  @if $level == 'AAA' {
    @return if($size == 'large', $ratio >= 4.5, $ratio >= 7);
  } @else {
    @return if($size == 'large', $ratio >= 3, $ratio >= 4.5);
  }
}

// Usage
$bg: #1976d2;
$text: #ffffff;

@debug contrast-ratio($text, $bg); // 4.53
@debug is-accessible($text, $bg); // true
@debug is-accessible($text, $bg, 'AAA'); // false

Example: Auto-adjust colors for accessibility

// Choose best text color (black or white)
@function text-color($bg, $light: #ffffff, $dark: #000000) {
  $light-ratio: contrast-ratio($light, $bg);
  $dark-ratio: contrast-ratio($dark, $bg);
  
  @return if($light-ratio > $dark-ratio, $light, $dark);
}

// Ensure accessible color
@function accessible-color($fg, $bg, $target-ratio: 4.5) {
  $ratio: contrast-ratio($fg, $bg);
  
  @if $ratio >= $target-ratio {
    @return $fg;
  }
  
  // Try darkening
  $darkened: $fg;
  @for $i from 1 through 20 {
    $darkened: darken($darkened, 5%);
    @if contrast-ratio($darkened, $bg) >= $target-ratio {
      @return $darkened;
    }
  }
  
  // Try lightening
  $lightened: $fg;
  @for $i from 1 through 20 {
    $lightened: lighten($lightened, 5%);
    @if contrast-ratio($lightened, $bg) >= $target-ratio {
      @return $lightened;
    }
  }
  
  // Fallback to black or white
  @return text-color($bg);
}

// Mixin for accessible text
@mixin accessible-text($bg, $level: 'AA') {
  $target: if($level == 'AAA', 7, 4.5);
  color: accessible-color(inherit, $bg, $target);
}

// Usage
.button {
  background: #ff9800;
  @include accessible-text(#ff9800);
}

.badge {
  $bg: #e3f2fd;
  background: $bg;
  color: text-color($bg);
}

Example: Accessibility validation mixin

// Validate and warn about contrast issues
@mixin validate-contrast($fg, $bg, $context: '') {
  $ratio: contrast-ratio($fg, $bg);
  
  @if $ratio < 3 {
    @error '#{$context} Contrast ratio #{$ratio} fails WCAG (minimum 3:1)';
  } @else if $ratio < 4.5 {
    @warn '#{$context} Contrast ratio #{$ratio} passes for large text only';
  } @else if $ratio < 7 {
    @warn '#{$context} Contrast ratio #{$ratio} passes AA but not AAA';
  }
}

// Auto-validate color usage
@mixin color-with-validation($property, $color, $bg, $context: '') {
  @include validate-contrast($color, $bg, $context);
  #{$property}: $color;
}

// Usage
.button-primary {
  $bg: #1976d2;
  background: $bg;
  @include color-with-validation(color, #ffffff, $bg, 'Button primary');
}

// Generate accessible palette
@function accessible-palette($base, $bg: #ffffff) {
  $palette: ();
  
  @for $i from 1 through 9 {
    $shade: darken($base, $i * 10%);
    @if is-accessible($shade, $bg) {
      $palette: append($palette, $shade);
    }
  }
  
  @return $palette;
}

14.5 Dynamic Color Manipulation Functions

Function Syntax Description Use Case
adjust-hue() adjust-hue($color, $degrees) Rotate hue on color wheel Color variations
saturate() saturate($color, $amount) Increase saturation Make colors vibrant
desaturate() desaturate($color, $amount) Decrease saturation Muted colors
mix() mix($color1, $color2, $weight) Blend two colors Color transitions
scale-color() scale-color($color, $red: 0%) Scale RGB/HSL values Precise adjustments
change-color() change-color($color, $hue: 0) Set specific channel Direct manipulation
complement() complement($color) Opposite hue (180°) Complementary colors
invert() invert($color, $weight) Invert RGB values Negative colors
grayscale() grayscale($color) Remove saturation Monochrome

Example: Advanced color manipulation utilities

@use 'sass:color';

// Smart color adjustment based on lightness
@function smart-scale($color, $amount) {
  $lightness: color.lightness($color);
  
  @if $lightness > 70% {
    @return darken($color, $amount);
  } @else if $lightness < 30% {
    @return lighten($color, $amount);
  } @else {
    @return saturate($color, $amount);
  }
}

// Create tint (mix with white)
@function tint($color, $percentage) {
  @return mix(white, $color, $percentage);
}

// Create shade (mix with black)
@function shade($color, $percentage) {
  @return mix(black, $color, $percentage);
}

// Create tone (mix with gray)
@function tone($color, $percentage) {
  @return mix(gray, $color, $percentage);
}

// Alpha transparency
@function alpha($color, $opacity) {
  @return rgba($color, $opacity);
}

// Multi-step color transformation
@function transform-color($color, $transforms...) {
  $result: $color;
  
  @each $transform in $transforms {
    $fn: nth($transform, 1);
    $args: if(length($transform) > 1, nth($transform, 2), null);
    
    @if $fn == 'lighten' {
      $result: lighten($result, $args);
    } @else if $fn == 'darken' {
      $result: darken($result, $args);
    } @else if $fn == 'saturate' {
      $result: saturate($result, $args);
    } @else if $fn == 'adjust-hue' {
      $result: adjust-hue($result, $args);
    }
  }
  
  @return $result;
}

// Usage
$base: #1976d2;
$tinted: tint($base, 20%);
$shaded: shade($base, 20%);
$toned: tone($base, 30%);

.button {
  background: transform-color($base, 
    (darken, 10%), 
    (saturate, 20%)
  );
}

Example: Color harmony and relationship functions

// Get complementary color
@function complementary($color) {
  @return adjust-hue($color, 180deg);
}

// Get analogous colors
@function analogous($color, $angle: 30deg) {
  @return (
    adjust-hue($color, -$angle),
    $color,
    adjust-hue($color, $angle)
  );
}

// Get triadic colors
@function triadic($color) {
  @return (
    $color,
    adjust-hue($color, 120deg),
    adjust-hue($color, 240deg)
  );
}

// Get split-complementary
@function split-complementary($color, $angle: 150deg) {
  @return (
    $color,
    adjust-hue($color, $angle),
    adjust-hue($color, -$angle)
  );
}

// Get tetradic (rectangle)
@function tetradic($color, $offset: 60deg) {
  @return (
    $color,
    adjust-hue($color, $offset),
    adjust-hue($color, 180deg),
    adjust-hue($color, 180deg + $offset)
  );
}

// Color temperature shift
@function warm($color, $amount: 10%) {
  @return adjust-hue($color, -$amount * 3.6deg);
}

@function cool($color, $amount: 10%) {
  @return adjust-hue($color, $amount * 3.6deg);
}

// Perceptual lightness adjustment
@function perceptual-lighten($color, $amount) {
  @return scale-color($color, $lightness: $amount);
}

@function perceptual-darken($color, $amount) {
  @return scale-color($color, $lightness: -$amount);
}

Example: State color generation

// Generate all button states from base color
@function button-states($base) {
  @return (
    default: $base,
    hover: darken($base, 8%),
    active: darken($base, 12%),
    focus: $base,
    disabled: desaturate(lighten($base, 20%), 40%),
    loading: desaturate($base, 20%)
  );
}

// Generate input states
@function input-states($base-border: #ccc) {
  @return (
    default: $base-border,
    hover: darken($base-border, 10%),
    focus: adjust-hue($base-border, 200deg),
    error: #f44336,
    success: #4caf50,
    disabled: lighten($base-border, 10%)
  );
}

// Mixin to apply all states
@mixin button-colors($base) {
  $states: button-states($base);
  
  background: map-get($states, default);
  
  &:hover:not(:disabled) {
    background: map-get($states, hover);
  }
  
  &:active:not(:disabled) {
    background: map-get($states, active);
  }
  
  &:focus-visible {
    outline: 2px solid map-get($states, focus);
    outline-offset: 2px;
  }
  
  &:disabled {
    background: map-get($states, disabled);
    cursor: not-allowed;
    opacity: 0.6;
  }
}

// Usage
.btn-primary {
  @include button-colors(#1976d2);
}

.btn-success {
  @include button-colors(#4caf50);
}

14.6 Color Token Systems and Design System Integration

Pattern Structure Description Example
Core Tokens Base color values Primitive colors $blue-500: #1976d2
Semantic Tokens Purpose-based names Functional colors $color-primary: $blue-500
Component Tokens Component-specific Scoped colors $button-bg: $color-primary
Token Aliasing Reference other tokens Single source of truth $link: $color-primary
Token Scale Numbered variations Consistent gradations 50, 100, 200...900
Theme Tokens Mode-specific values Light/dark variants $bg-light, $bg-dark

Example: Three-tier token system

// ===== TIER 1: Core/Primitive Tokens =====
// These are the base color values
$blue-50: #e3f2fd;
$blue-100: #bbdefb;
$blue-200: #90caf9;
$blue-300: #64b5f6;
$blue-400: #42a5f5;
$blue-500: #2196f3;
$blue-600: #1e88e5;
$blue-700: #1976d2;
$blue-800: #1565c0;
$blue-900: #0d47a1;

$gray-50: #fafafa;
$gray-100: #f5f5f5;
$gray-200: #eeeeee;
$gray-300: #e0e0e0;
// ... more grays

$red-500: #f44336;
$green-500: #4caf50;
$orange-500: #ff9800;

// ===== TIER 2: Semantic Tokens =====
// Purpose-based tokens
$color-primary: $blue-700;
$color-primary-light: $blue-500;
$color-primary-dark: $blue-900;

$color-secondary: $red-500;
$color-success: $green-500;
$color-warning: $orange-500;
$color-error: $red-500;
$color-info: $blue-500;

// Background tokens
$color-background: $gray-50;
$color-surface: #ffffff;
$color-overlay: rgba(0, 0, 0, 0.5);

// Text tokens
$color-text-primary: rgba(0, 0, 0, 0.87);
$color-text-secondary: rgba(0, 0, 0, 0.60);
$color-text-disabled: rgba(0, 0, 0, 0.38);
$color-text-hint: rgba(0, 0, 0, 0.38);

// Border tokens
$color-border: $gray-300;
$color-divider: rgba(0, 0, 0, 0.12);

// ===== TIER 3: Component Tokens =====
// Component-specific tokens
$button-bg-primary: $color-primary;
$button-text-primary: #ffffff;
$button-bg-secondary: $color-secondary;
$button-border-radius: 4px;

$input-bg: $color-surface;
$input-border: $color-border;
$input-text: $color-text-primary;
$input-placeholder: $color-text-secondary;

$card-bg: $color-surface;
$card-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);

$link-color: $color-primary;
$link-hover: $color-primary-dark;

Example: Design system integration with Style Dictionary

// tokens.scss - Source tokens in SCSS format
$tokens: (
  color: (
    core: (
      blue: (
        50: #e3f2fd,
        100: #bbdefb,
        500: #2196f3,
        900: #0d47a1
      ),
      gray: (
        50: #fafafa,
        500: #9e9e9e,
        900: #212121
      )
    ),
    semantic: (
      primary: (
        default: '{color.core.blue.500}',
        light: '{color.core.blue.50}',
        dark: '{color.core.blue.900}'
      ),
      text: (
        primary: '{color.core.gray.900}',
        secondary: '{color.core.gray.500}'
      )
    ),
    component: (
      button: (
        background: '{color.semantic.primary.default}',
        text: '#ffffff',
        hover: '{color.semantic.primary.dark}'
      ),
      input: (
        background: '#ffffff',
        border: '{color.core.gray.500}',
        text: '{color.semantic.text.primary}'
      )
    )
  ),
  spacing: (
    xs: 4px,
    sm: 8px,
    md: 16px,
    lg: 24px,
    xl: 32px
  )
);

// Token resolver function
@function resolve-token($path) {
  // Parse token reference like '{color.core.blue.500}'
  @if str-index($path, '{') {
    $clean: str-slice($path, 2, -2); // Remove { }
    $keys: split-string($clean, '.');
    
    $value: $tokens;
    @each $key in $keys {
      $value: map-get($value, $key);
    }
    
    @return $value;
  }
  @return $path;
}

// Generate CSS custom properties
@mixin generate-css-vars($map, $prefix: '') {
  @each $key, $value in $map {
    @if type-of($value) == 'map' {
      @include generate-css-vars($value, '#{$prefix}#{$key}-');
    } @else {
      --#{$prefix}#{$key}: #{resolve-token($value)};
    }
  }
}

:root {
  @include generate-css-vars(map-get($tokens, color), 'color-');
  @include generate-css-vars(map-get($tokens, spacing), 'spacing-');
}

Example: Multi-brand token system

// Brand token configuration
$brands: (
  acme: (
    primary: #1976d2,
    secondary: #dc004e,
    logo: url('/brands/acme-logo.svg')
  ),
  globex: (
    primary: #4caf50,
    secondary: #ff9800,
    logo: url('/brands/globex-logo.svg')
  ),
  initech: (
    primary: #9c27b0,
    secondary: #00bcd4,
    logo: url('/brands/initech-logo.svg')
  )
);

// Generate brand-specific tokens
@each $brand-name, $brand-config in $brands {
  [data-brand="#{$brand-name}"] {
    --brand-primary: #{map-get($brand-config, primary)};
    --brand-secondary: #{map-get($brand-config, secondary)};
    --brand-logo: #{map-get($brand-config, logo)};
    
    // Generate palette from primary
    --brand-primary-light: #{lighten(map-get($brand-config, primary), 20%)};
    --brand-primary-dark: #{darken(map-get($brand-config, primary), 20%)};
    
    // Generate contrast colors
    --brand-on-primary: #{text-color(map-get($brand-config, primary))};
    --brand-on-secondary: #{text-color(map-get($brand-config, secondary))};
  }
}

// Component usage
.header {
  background: var(--brand-primary);
  color: var(--brand-on-primary);
  
  &__logo {
    background-image: var(--brand-logo);
  }
}

.button-primary {
  background: var(--brand-primary);
  color: var(--brand-on-primary);
  
  &:hover {
    background: var(--brand-primary-dark);
  }
}

Example: Token documentation generator

// Generate color documentation
@mixin document-colors($color-map, $name: '') {
  @if type-of($color-map) == 'color' {
    // Generate a swatch
    .color-swatch-#{$name} {
      &::before {
        content: '#{$name}: #{$color-map}';
        display: inline-block;
        width: 100px;
        height: 40px;
        background: $color-map;
        margin-right: 10px;
        border: 1px solid #ccc;
      }
    }
  } @else if type-of($color-map) == 'map' {
    @each $key, $value in $color-map {
      $full-name: if($name == '', $key, '#{$name}-#{$key}');
      @include document-colors($value, $full-name);
    }
  }
}

// Generate documentation
@include document-colors($tokens);

// Export as JSON for documentation tools
@function tokens-to-json($map, $indent: 0) {
  $json: '{\n';
  $i: 0;
  
  @each $key, $value in $map {
    $i: $i + 1;
    $spacing: '';
    @for $s from 1 through ($indent + 1) {
      $spacing: $spacing + '  ';
    }
    
    $json: $json + $spacing + '"#{$key}": ';
    
    @if type-of($value) == 'map' {
      $json: $json + tokens-to-json($value, $indent + 1);
    } @else {
      $json: $json + '"#{$value}"';
    }
    
    @if $i < length($map) {
      $json: $json + ',';
    }
    $json: $json + '\n';
  }
  
  $spacing: '';
  @for $s from 1 through $indent {
    $spacing: $spacing + '  ';
  }
  $json: $json + $spacing + '}';
  
  @return $json;
}

Color Management Best Practices

  • Three-tier tokens: Core → Semantic → Component for scalability
  • CSS variables: Enable runtime theme switching and scoping
  • Accessibility first: Always validate contrast ratios (4.5:1 minimum)
  • Dark mode: Use hybrid approach (media query + manual toggle)
  • Semantic naming: Use purpose-based names, not color names
  • Automated generation: Generate palettes and states programmatically
  • Design tokens: Single source of truth for multi-platform consistency
  • Contrast functions: Validate and auto-adjust colors for WCAG compliance
Note: Modern Sass modules (sass:color) provide more precise color manipulation with better support for different color spaces. Use @use 'sass:color' for future-proof implementations.

15. Performance Optimization and Compilation

15.1 Output Style Configuration (compressed, expanded)

Output Style Description Use Case Size Impact
compressed Minified, single line Production deployment Smallest (30-40% reduction)
expanded Standard CSS formatting Development, debugging Largest, most readable
compact Each rule on one line Legacy compatibility Medium compression
nested Nested like SCSS source Understanding output structure Medium, preserves hierarchy

Example: CLI output style configuration

// Compressed (production)
sass --style=compressed input.scss output.css

// Expanded (development)
sass --style=expanded input.scss output.css

// With watch mode
sass --watch --style=compressed src/scss:dist/css

// Multiple files
sass --style=compressed src/scss:dist/css --no-source-map

Example: Package.json scripts configuration

{
  "scripts": {
    "sass:dev": "sass --watch --style=expanded src/scss:dist/css",
    "sass:build": "sass --style=compressed --no-source-map src/scss:dist/css",
    "sass:prod": "sass --style=compressed src/scss:dist/css && postcss dist/css/*.css --replace",
    "sass:analyze": "sass --style=expanded src/scss:dist/css --embed-sources"
  },
  "devDependencies": {
    "sass": "^1.69.0",
    "postcss": "^8.4.31",
    "autoprefixer": "^10.4.16",
    "cssnano": "^6.0.1"
  }
}

Example: Node.js API configuration

const sass = require('sass');
const fs = require('fs');

// Development build
const devResult = sass.compile('src/main.scss', {
  style: 'expanded',
  sourceMap: true,
  sourceMapIncludeSources: true
});

fs.writeFileSync('dist/main.css', devResult.css);
fs.writeFileSync('dist/main.css.map', JSON.stringify(devResult.sourceMap));

// Production build
const prodResult = sass.compile('src/main.scss', {
  style: 'compressed',
  sourceMap: false,
  quietDeps: true,
  verbose: false
});

fs.writeFileSync('dist/main.min.css', prodResult.css);

// Output comparison
console.log(`Dev size: ${devResult.css.length} bytes`);
console.log(`Prod size: ${prodResult.css.length} bytes`);
console.log(`Reduction: ${((1 - prodResult.css.length / devResult.css.length) * 100).toFixed(1)}%`);

15.2 Source Map Generation and Debugging

Option Flag Description Impact
Source Map --source-map Generate .css.map file Enable DevTools debugging
Inline Map --embed-source-map Embed map in CSS Single file, larger CSS
Embed Sources --embed-sources Include SCSS in map Full debugging without files
No Source Map --no-source-map Disable map generation Production, smallest output
Source Map URLs --source-map-urls absolute/relative paths Control URL resolution

Example: Source map configuration for different environments

// Development - Full debugging capability
sass --watch \
  --style=expanded \
  --source-map \
  --embed-sources \
  src/scss:dist/css

// Staging - External source maps
sass --style=compressed \
  --source-map \
  --source-map-urls=relative \
  src/scss:dist/css

// Production - No source maps
sass --style=compressed \
  --no-source-map \
  src/scss:dist/css

// Debug mode - Everything embedded
sass --style=expanded \
  --embed-source-map \
  --embed-sources \
  src/main.scss dist/main.css

Example: Webpack sass-loader configuration

// webpack.config.js
module.exports = {
  mode: process.env.NODE_ENV || 'development',
  devtool: 'source-map',
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              sourceMap: true,
              importLoaders: 2
            }
          },
          {
            loader: 'postcss-loader',
            options: {
              sourceMap: true
            }
          },
          {
            loader: 'sass-loader',
            options: {
              sourceMap: true,
              sassOptions: {
                outputStyle: process.env.NODE_ENV === 'production' 
                  ? 'compressed' 
                  : 'expanded',
                sourceMapContents: true,
                sourceMapEmbed: false
              }
            }
          }
        ]
      }
    ]
  }
};

Example: Browser DevTools debugging workflow

// styles.scss (source file)
.button {
  $base-color: #1976d2;
  
  background: $base-color;
  color: white;
  
  &:hover {
    background: darken($base-color, 10%);
  }
}

// In browser DevTools with source maps:
// 1. Open DevTools → Sources tab
// 2. Navigate to webpack:// or scss:// folder
// 3. See original .scss files with line numbers
// 4. Set breakpoints (for CSS changes)
// 5. Inspect shows:
//    styles.scss:4 → background: $base-color;
//    Not: styles.css:1 → background: #1976d2;

// Source map enables:
// - See which .scss file generated each rule
// - View original variable names and mixins
// - Edit SCSS directly in DevTools (with workspaces)
// - Accurate error reporting with SCSS line numbers

15.3 Build Tool Integration (Webpack, Vite, Parcel)

Tool Loader/Plugin Configuration Features
Webpack sass-loader Complex, powerful Full control, optimization
Vite Built-in Zero-config Fast HMR, modern
Parcel Built-in Zero-config Auto-install, simple
esbuild esbuild-sass-plugin Minimal config Extremely fast
Rollup rollup-plugin-scss Plugin-based Library bundling
// vite.config.js
import { defineConfig } from 'vite';

export default defineConfig({
  css: {
    preprocessorOptions: {
      scss: {
        // Global variables/mixins available in all components
        additionalData: `@use "src/styles/variables" as *;`,
        
        // Modern Sass API
        api: 'modern-compiler',
        
        // Include paths for @use/@import resolution
        includePaths: ['node_modules', 'src/styles']
      }
    },
    
    // PostCSS configuration
    postcss: {
      plugins: [
        require('autoprefixer'),
        require('cssnano')({
          preset: ['default', {
            discardComments: { removeAll: true }
          }]
        })
      ]
    },
    
    devSourcemap: true
  },
  
  build: {
    cssCodeSplit: true,
    cssMinify: true,
    sourcemap: true
  }
});

Example: Webpack 5 comprehensive configuration

// webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const path = require('path');

module.exports = {
  mode: process.env.NODE_ENV || 'development',
  
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: [
          // Extract to separate file
          MiniCssExtractPlugin.loader,
          
          // CSS loader
          {
            loader: 'css-loader',
            options: {
              importLoaders: 2,
              sourceMap: true,
              modules: {
                auto: true,
                localIdentName: '[name]__[local]--[hash:base64:5]'
              }
            }
          },
          
          // PostCSS (autoprefixer, etc.)
          {
            loader: 'postcss-loader',
            options: {
              sourceMap: true,
              postcssOptions: {
                plugins: ['autoprefixer', 'cssnano']
              }
            }
          },
          
          // Sass compiler
          {
            loader: 'sass-loader',
            options: {
              sourceMap: true,
              sassOptions: {
                outputStyle: 'compressed',
                includePaths: [
                  path.resolve(__dirname, 'src/styles'),
                  path.resolve(__dirname, 'node_modules')
                ]
              },
              // Global imports
              additionalData: `
                @use 'sass:math';
                @use 'variables' as *;
                @use 'mixins' as *;
              `
            }
          }
        ]
      }
    ]
  },
  
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css',
      chunkFilename: '[id].[contenthash].css'
    })
  ],
  
  optimization: {
    minimizer: [
      `...`, // Extend existing minimizers
      new CssMinimizerPlugin({
        minimizerOptions: {
          preset: ['default', {
            discardComments: { removeAll: true },
            normalizeWhitespace: true,
            colormin: true,
            minifyFontValues: true
          }]
        }
      })
    ]
  }
};

Example: Parcel zero-config setup

// package.json
{
  "name": "my-project",
  "scripts": {
    "dev": "parcel src/index.html",
    "build": "parcel build src/index.html --no-source-maps"
  },
  "devDependencies": {
    "parcel": "^2.10.0",
    "sass": "^1.69.0"
  }
}

// .sassrc.json (optional configuration)
{
  "includePaths": ["src/styles", "node_modules"],
  "outputStyle": "compressed",
  "sourceMap": true
}

// index.html
<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="./styles/main.scss">
</head>
<body>
  <!-- Content -->
</body>
</html>

// Parcel automatically:
// 1. Detects .scss files
// 2. Installs sass if needed
// 3. Compiles SCSS → CSS
// 4. Applies PostCSS transformations
// 5. Minifies for production
// 6. Generates source maps

Example: esbuild plugin configuration (fastest build)

// build.js
const esbuild = require('esbuild');
const sassPlugin = require('esbuild-sass-plugin').default;

esbuild.build({
  entryPoints: ['src/main.scss'],
  outfile: 'dist/main.css',
  bundle: true,
  minify: true,
  sourcemap: true,
  
  plugins: [
    sassPlugin({
      // Sass options
      style: 'compressed',
      sourceMap: true,
      
      // PostCSS integration
      async transform(source, resolveDir) {
        const postcss = require('postcss');
        const autoprefixer = require('autoprefixer');
        
        const result = await postcss([autoprefixer])
          .process(source, { from: undefined });
        
        return result.css;
      }
    })
  ],
  
  loader: {
    '.scss': 'css',
    '.sass': 'css'
  }
}).then(() => {
  console.log('Build complete!');
}).catch(() => process.exit(1));

15.4 Compilation Speed Optimization Techniques

Technique Method Impact Trade-off
Use @use/@forward Replace @import 20-40% faster Migration effort
Limit Nesting Max 3-4 levels 10-20% faster Flatter structure
Avoid @extend Use @mixin instead 15-25% faster Slightly larger CSS
Cache Dependencies Enable build caching 50-80% faster rebuilds Disk space
Dart Sass Use modern compiler 2-3x faster than node-sass None (recommended)
Partial Imports Import only needed files Proportional to reduction Manual management
Parallel Processing Multiple workers 30-50% on multi-core Complex setup

Example: Migration to @use for better performance

// ❌ SLOW: Old @import (loads everything, no namespacing)
@import 'variables';
@import 'mixins';
@import 'functions';
@import 'components/button';
@import 'components/card';
// File loaded multiple times if imported elsewhere

// ✅ FAST: Modern @use (loads once, namespaced, tree-shakeable)
@use 'variables' as vars;
@use 'mixins' as mix;
@use 'functions' as fn;
@use 'components/button';
@use 'components/card';

// Each file loaded exactly once across entire project
// Compiler can optimize unused exports
// Explicit namespacing prevents conflicts

// Performance comparison:
// @import: ~800ms compile time
// @use:    ~450ms compile time (44% faster)

Example: Webpack caching configuration

// webpack.config.js
module.exports = {
  cache: {
    type: 'filesystem',
    cacheDirectory: path.resolve(__dirname, '.webpack-cache'),
    buildDependencies: {
      config: [__filename]
    }
  },
  
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              // Enable CSS modules caching
              modules: {
                mode: 'local',
                localIdentContext: path.resolve(__dirname, 'src'),
                // Consistent hashing for better caching
                localIdentHashFunction: 'md4',
                localIdentHashDigest: 'base64',
                localIdentHashDigestLength: 8
              }
            }
          },
          {
            loader: 'sass-loader',
            options: {
              // Enable Sass result caching
              sassOptions: {
                // Use modern compiler
                api: 'modern',
                // Silence dependency warnings for faster compilation
                quietDeps: true,
                verbose: false
              }
            }
          }
        ]
      }
    ]
  },
  
  optimization: {
    moduleIds: 'deterministic',
    runtimeChunk: 'single',
    splitChunks: {
      cacheGroups: {
        styles: {
          name: 'styles',
          type: 'css/mini-extract',
          chunks: 'all',
          enforce: true
        }
      }
    }
  }
};

// First build: ~2500ms
// Cached rebuild: ~450ms (82% faster)

Example: Optimized file structure for fast compilation

// ❌ SLOW: Monolithic structure
// main.scss imports everything
@use 'base';      // 50 variables
@use 'mixins';    // 30 mixins
@use 'utilities'; // 100 utility classes
// Every component recompiles when any part changes

// ✅ FAST: Modular structure with targeted imports
// abstracts/_index.scss
@forward 'variables';
@forward 'functions';
@forward 'mixins';

// components/button/_button.scss
@use '../../abstracts' as *;
// Only loads what's needed

// components/card/_card.scss
@use '../../abstracts' as *;
// Shared abstracts loaded once by compiler

// main.scss
@use 'abstracts';
@use 'components/button';
@use 'components/card';

// File organization for speed:
styles/
├── abstracts/
│   ├── _index.scss       # Forward only
│   ├── _variables.scss   # Pure data (fast)
│   ├── _functions.scss   # Pure functions (fast)
│   └── _mixins.scss      # Reusable code
├── base/
│   └── _reset.scss       # Minimal, rarely changes
├── components/
│   ├── _button.scss      # Independent modules
│   └── _card.scss        # Can compile in parallel
└── main.scss             # Thin orchestrator

// Benchmark:
// Monolithic: Change 1 variable → 2000ms recompile
// Modular:    Change 1 variable → 400ms recompile (80% faster)

15.5 CSS Output Size Reduction Strategies

Strategy Implementation Reduction Notes
Use @extend Share selectors 10-30% Careful with specificity
Placeholder Selectors %silent classes 15-25% Not output unless extended
Avoid Deep Nesting Flatten selectors 5-15% Better performance too
Compression style=compressed 30-40% Essential for production
PurgeCSS Remove unused CSS 50-90% Especially with frameworks
CSS Minification PostCSS cssnano 10-20% additional After Sass compilation
Tree Shaking @use instead of @import 20-40% Modern module system

Example: Placeholder selectors for size optimization

// Using placeholder selectors (not output unless extended)
%card-base {
  padding: 1rem;
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

%flex-center {
  display: flex;
  align-items: center;
  justify-content: center;
}

// These extend the placeholder (selector grouping in output)
.product-card {
  @extend %card-base;
  background: white;
}

.user-card {
  @extend %card-base;
  background: #f5f5f5;
}

.modal-header {
  @extend %flex-center;
  height: 60px;
}

// CSS Output (optimized):
.product-card, .user-card {
  padding: 1rem;
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.product-card { background: white; }
.user-card { background: #f5f5f5; }
.modal-header {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 60px;
}

// Size comparison:
// Without placeholders: 280 bytes
// With placeholders:    185 bytes (34% smaller)

Example: PurgeCSS integration for unused CSS removal

// postcss.config.js
const purgecss = require('@fullhuman/postcss-purgecss');

module.exports = {
  plugins: [
    require('autoprefixer'),
    
    // Only in production
    ...(process.env.NODE_ENV === 'production' ? [
      purgecss({
        content: [
          './src/**/*.html',
          './src/**/*.jsx',
          './src/**/*.tsx',
          './src/**/*.vue'
        ],
        
        // Default extractors
        defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || [],
        
        // Safe list (never purge)
        safelist: {
          standard: ['active', 'disabled', 'hidden'],
          deep: [/^modal-/, /^dropdown-/],
          greedy: [/^data-/]
        },
        
        // Purge from variables too
        variables: true,
        
        // Keep keyframes if any animation uses them
        keyframes: true
      })
    ] : []),
    
    require('cssnano')({
      preset: ['default', {
        discardComments: { removeAll: true },
        normalizeWhitespace: true
      }]
    })
  ]
};

// package.json
{
  "scripts": {
    "build:css": "sass src/styles:dist/css && postcss dist/css/*.css --replace"
  }
}

// Size reduction example:
// Before PurgeCSS: 450KB
// After PurgeCSS:  45KB (90% reduction)

Example: Complete optimization pipeline

// build-css.js - Comprehensive optimization
const sass = require('sass');
const postcss = require('postcss');
const autoprefixer = require('autoprefixer');
const cssnano = require('cssnano');
const purgecss = require('@fullhuman/postcss-purgecss');
const fs = require('fs').promises;
const path = require('path');

async function buildCSS() {
  console.time('Total build time');
  
  // Step 1: Compile Sass
  console.time('Sass compilation');
  const sassResult = sass.compile('src/styles/main.scss', {
    style: 'expanded', // Will minify later for better optimization
    sourceMap: false,
    quietDeps: true
  });
  console.timeEnd('Sass compilation');
  console.log(`Compiled size: ${(sassResult.css.length / 1024).toFixed(2)}KB`);
  
  // Step 2: PostCSS transformations
  console.time('PostCSS processing');
  const plugins = [
    autoprefixer(),
    purgecss({
      content: ['src/**/*.html', 'src/**/*.js'],
      defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || []
    }),
    cssnano({
      preset: ['advanced', {
        discardComments: { removeAll: true },
        reduceIdents: true,
        mergeRules: true,
        mergeLonghand: true,
        colormin: true,
        normalizeWhitespace: true,
        discardUnused: true,
        minifyFontValues: true,
        minifySelectors: true
      }]
    })
  ];
  
  const result = await postcss(plugins).process(sassResult.css, {
    from: 'main.scss',
    to: 'main.css'
  });
  console.timeEnd('PostCSS processing');
  
  // Step 3: Write output
  await fs.writeFile('dist/main.css', result.css);
  console.log(`Final size: ${(result.css.length / 1024).toFixed(2)}KB`);
  console.log(`Reduction: ${((1 - result.css.length / sassResult.css.length) * 100).toFixed(1)}%`);
  
  console.timeEnd('Total build time');
}

buildCSS().catch(console.error);

// Example output:
// Sass compilation: 245ms
// Compiled size: 450.32KB
// PostCSS processing: 892ms
// Final size: 42.18KB
// Reduction: 90.6%
// Total build time: 1.142s

15.6 Watch Mode and Live Reloading Setup

Tool Command Features Use Case
Sass CLI sass --watch File watching, auto-compile Simple projects
Vite vite dev HMR, instant updates Modern development
Webpack Dev Server webpack serve HMR, proxy, history Complex apps
Browser Sync browsersync start Multi-device sync Cross-browser testing
Nodemon nodemon --watch Custom commands Custom workflows

Example: Sass CLI watch mode

// Basic watch mode
sass --watch src/scss:dist/css

// Watch with options
sass --watch \
  --style=expanded \
  --source-map \
  --embed-sources \
  src/scss:dist/css

// Watch specific file
sass --watch src/styles/main.scss:dist/css/main.css

// Watch with polling (for network drives, Docker)
sass --watch --poll src/scss:dist/css

// Multiple watch targets
sass --watch \
  src/scss/app:dist/css/app \
  src/scss/admin:dist/css/admin

// package.json scripts
{
  "scripts": {
    "watch": "sass --watch src/scss:dist/css",
    "watch:dev": "sass --watch --style=expanded --source-map src/scss:dist/css",
    "watch:prod": "sass --watch --style=compressed --no-source-map src/scss:dist/css"
  }
}

Example: Vite with HMR (Hot Module Replacement)

// vite.config.js
import { defineConfig } from 'vite';

export default defineConfig({
  server: {
    port: 3000,
    open: true,
    
    // HMR configuration
    hmr: {
      overlay: true, // Show errors as overlay
      clientPort: 3000
    },
    
    // Watch options
    watch: {
      usePolling: false, // Set true for Docker/WSL
      interval: 100
    }
  },
  
  css: {
    devSourcemap: true,
    preprocessorOptions: {
      scss: {
        // Inject global styles
        additionalData: `@use "src/styles/globals" as *;`
      }
    }
  }
});

// App component automatically reloads on SCSS changes
// Changes appear instantly without full page reload

// package.json
{
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  }
}

Example: Browser-sync with Sass watching

// bs-config.js
module.exports = {
  files: ['dist/**/*.css', 'src/**/*.html', 'src/**/*.js'],
  server: {
    baseDir: 'dist',
    index: 'index.html'
  },
  port: 3000,
  open: true,
  notify: false,
  
  // CSS injection (no page reload)
  injectChanges: true,
  
  // Reload delay
  reloadDelay: 0,
  
  // Multi-device sync
  ghostMode: {
    clicks: true,
    forms: true,
    scroll: true
  }
};

// watch-and-serve.js
const { spawn } = require('child_process');
const browserSync = require('browser-sync').create();

// Start Sass watcher
const sassProcess = spawn('sass', [
  '--watch',
  '--style=expanded',
  'src/scss:dist/css'
], { stdio: 'inherit' });

// Start BrowserSync
browserSync.init({
  server: 'dist',
  files: ['dist/**/*.css', 'src/**/*.html'],
  port: 3000,
  notify: false
});

// Cleanup on exit
process.on('SIGINT', () => {
  sassProcess.kill();
  browserSync.exit();
  process.exit();
});

// package.json
{
  "scripts": {
    "dev": "node watch-and-serve.js"
  },
  "devDependencies": {
    "browser-sync": "^2.29.3",
    "sass": "^1.69.0"
  }
}

Example: Custom watch script with live reload

// dev-server.js - Custom development server
const chokidar = require('chokidar');
const sass = require('sass');
const fs = require('fs').promises;
const path = require('path');
const { WebSocketServer } = require('ws');
const express = require('express');

const app = express();
const PORT = 3000;

// Serve static files
app.use(express.static('dist'));

// Inject live reload script
app.get('/', async (req, res) => {
  let html = await fs.readFile('dist/index.html', 'utf-8');
  html = html.replace('</body>', `
    <script>
      const ws = new WebSocket('ws://localhost:${PORT + 1}');
      ws.onmessage = (msg) => {
        if (msg.data === 'css-update') {
          // Hot reload CSS without page refresh
          const links = document.querySelectorAll('link[rel="stylesheet"]');
          links.forEach(link => {
            const href = link.href.split('?')[0];
            link.href = href + '?t=' + Date.now();
          });
        } else if (msg.data === 'reload') {
          location.reload();
        }
      };
    </script>
  </body>`);
  res.send(html);
});

// WebSocket server for live reload
const wss = new WebSocketServer({ port: PORT + 1 });
const clients = new Set();

wss.on('connection', (ws) => {
  clients.add(ws);
  ws.on('close', () => clients.delete(ws));
});

function broadcast(message) {
  clients.forEach(client => {
    if (client.readyState === 1) client.send(message);
  });
}

// Watch SCSS files
const scssWatcher = chokidar.watch('src/scss/**/*.scss', {
  ignoreInitial: true
});

scssWatcher.on('change', async (filePath) => {
  console.log(`SCSS changed: ${filePath}`);
  
  try {
    const result = sass.compile('src/scss/main.scss', {
      style: 'expanded',
      sourceMap: true
    });
    
    await fs.writeFile('dist/css/main.css', result.css);
    console.log('CSS compiled successfully');
    
    broadcast('css-update');
  } catch (err) {
    console.error('Sass compilation error:', err.message);
  }
});

// Watch HTML files
const htmlWatcher = chokidar.watch('src/**/*.html', {
  ignoreInitial: true
});

htmlWatcher.on('change', (filePath) => {
  console.log(`HTML changed: ${filePath}`);
  broadcast('reload');
});

// Start server
app.listen(PORT, () => {
  console.log(`Dev server running at http://localhost:${PORT}`);
  console.log('Watching for changes...');
});

Performance Optimization Summary

  • Output styles: Use compressed for production, expanded for development
  • Source maps: Enable in dev/staging, disable in production
  • Modern tools: Vite offers best DX with zero-config and instant HMR
  • @use over @import: 20-40% faster compilation with better scoping
  • Caching: Enable filesystem cache for 50-80% faster rebuilds
  • Size reduction: Combine placeholders, PurgeCSS (50-90% reduction)
  • Watch mode: Use HMR for instant feedback without full reloads
  • Build pipeline: Sass → PostCSS → Autoprefixer → PurgeCSS → Minification
Note: Modern compilers like Dart Sass are 2-3x faster than deprecated node-sass. Always use the latest Sass version with the modern-compiler API for best performance.

16. Error Handling and Debugging Techniques

16.1 @debug Directive for Development Logging

Directive Syntax Output Use Case
@debug @debug $value; Prints to stderr Development logging
Multiple Values @debug $var1, $var2; Comma-separated output Compare values
Expressions @debug 10px + 5px; Evaluated result Test calculations
Type Inspection @debug type-of($var); Data type Type checking
Map Inspection @debug map-keys($map); Map structure Debug data structures

Example: Basic debugging with @debug

// Simple value debugging
$primary-color: #1976d2;
@debug $primary-color;
// Output: styles.scss:2 DEBUG: #1976d2

// Multiple values
$width: 300px;
$height: 200px;
@debug "Width:", $width, "Height:", $height;
// Output: styles.scss:5 DEBUG: "Width:", 300px, "Height:", 200px

// Expression debugging
@debug 100px / 16px; 
// Output: styles.scss:7 DEBUG: 6.25

// Type checking
$value: "hello";
@debug type-of($value);
// Output: styles.scss:9 DEBUG: string

// Map debugging
$theme: (
  primary: #1976d2,
  secondary: #dc004e
);
@debug map-keys($theme);
// Output: styles.scss:13 DEBUG: primary, secondary

@debug map-get($theme, primary);
// Output: styles.scss:15 DEBUG: #1976d2

Example: Advanced debugging techniques

@use 'sass:meta';
@use 'sass:map';

// Debug function for formatted output
@mixin debug-info($label, $value) {
  @debug "=== #{$label} ===";
  @debug "  Type: #{meta.type-of($value)}";
  @debug "  Value: #{$value}";
  
  @if meta.type-of($value) == 'map' {
    @debug "  Keys: #{map.keys($value)}";
    @debug "  Values: #{map.values($value)}";
  } @else if meta.type-of($value) == 'list' {
    @debug "  Length: #{length($value)}";
    @debug "  Items: #{$value}";
  }
}

// Usage
$colors: (
  primary: #1976d2,
  secondary: #dc004e,
  success: #4caf50
);

@include debug-info('Theme Colors', $colors);
// Output:
// === Theme Colors ===
//   Type: map
//   Value: (primary: #1976d2, secondary: #dc004e, success: #4caf50)
//   Keys: primary, secondary, success
//   Values: #1976d2, #dc004e, #4caf50

// Conditional debugging
$debug-mode: true;

@mixin debug($message) {
  @if $debug-mode {
    @debug $message;
  }
}

// Function debugging
@function calculate-rem($px) {
  @debug "Converting: #{$px}px to rem";
  $rem: $px / 16;
  @debug "Result: #{$rem}rem";
  @return $rem * 1rem;
}

$font-size: calculate-rem(18);
// Output:
// Converting: 18px to rem
// Result: 1.125rem

Example: Debug breakpoint in compilation

// Debug during loop iterations
$breakpoints: (
  xs: 0,
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px
);

@each $name, $size in $breakpoints {
  @debug "Processing breakpoint: #{$name} = #{$size}";
  
  @media (min-width: $size) {
    .container-#{$name} {
      @debug "  Creating .container-#{$name}";
      max-width: $size;
    }
  }
}

// Debug color transformations
@function debug-color-transform($color, $operation, $amount) {
  @debug "Original color: #{$color}";
  
  $result: null;
  @if $operation == 'lighten' {
    $result: lighten($color, $amount);
  } @else if $operation == 'darken' {
    $result: darken($color, $amount);
  }
  
  @debug "After #{$operation}(#{$amount}): #{$result}";
  @return $result;
}

$base: #1976d2;
$lighter: debug-color-transform($base, 'lighten', 20%);
// Output:
// Original color: #1976d2
// After lighten(20%): #64b5f6

16.2 @warn Directive for Deprecation Warnings

Directive Behavior Use Case Impact
@warn Prints warning, continues compilation Deprecation notices Non-fatal alerts
Stack Trace Shows file and line number Track warning source Easy debugging
Conditional Warnings Warn based on conditions Value validation Better error messages
--quiet Suppress warnings with flag Production builds Clean output

Example: Deprecation warnings

// Deprecation warning for old API
@mixin old-button($color) {
  @warn "The old-button mixin is deprecated. Use new-button instead.";
  background: $color;
  padding: 10px 20px;
}

// Better deprecation with migration path
@mixin legacy-grid($cols: 12) {
  @warn "legacy-grid is deprecated since v2.0. " +
        "Use CSS Grid with grid-template-columns instead. " +
        "See: https://docs.example.com/migration";
  
  width: 100% / $cols;
  float: left;
}

// Warn about parameter changes
@mixin button($bg-color, $text-color: null) {
  @if $text-color == null {
    @warn "The text-color parameter will become required in v3.0. " +
          "Please provide an explicit text color.";
    $text-color: white; // Fallback
  }
  
  background: $bg-color;
  color: $text-color;
}

// Usage triggers warning:
.my-button {
  @include button(#1976d2);
  // Warning: The text-color parameter will become required in v3.0...
}

Example: Value validation warnings

@use 'sass:math';
@use 'sass:meta';

// Warn about invalid values
@function safe-divide($a, $b) {
  @if $b == 0 {
    @warn "Division by zero! Returning 0 instead.";
    @return 0;
  }
  @return math.div($a, $b);
}

// Warn about type mismatches
@mixin font-size($size) {
  @if meta.type-of($size) != 'number' {
    @warn "font-size expects a number, got #{meta.type-of($size)}: #{$size}";
    @return;
  }
  
  @if not math.is-unitless($size) and math.unit($size) != 'px' and math.unit($size) != 'rem' {
    @warn "font-size expects px or rem units, got: #{math.unit($size)}";
  }
  
  font-size: $size;
}

// Warn about out-of-range values
@mixin opacity($value) {
  @if $value < 0 or $value > 1 {
    @warn "Opacity should be between 0 and 1, got: #{$value}. Clamping value.";
    $value: math.clamp(0, $value, 1);
  }
  
  opacity: $value;
}

// Warn about browser compatibility
@mixin backdrop-filter($value) {
  @warn "backdrop-filter has limited browser support. " +
        "Consider providing a fallback background color.";
  
  backdrop-filter: $value;
  -webkit-backdrop-filter: $value;
}

// Warn about performance concerns
@mixin deep-nesting-check($level) {
  @if $level > 3 {
    @warn "Nesting level #{$level} detected. " +
          "Deep nesting (>3 levels) can hurt performance and specificity.";
  }
}

Example: Configuration and environment warnings

// Warn about missing configuration
$config: () !default;

@function get-config($key) {
  @if not map-has-key($config, $key) {
    @warn "Configuration key '#{$key}' not found. Using default value.";
    @return null;
  }
  
  @return map-get($config, $key);
}

// Warn about conflicting settings
$use-flexbox: true !default;
$use-float: true !default;

@if $use-flexbox and $use-float {
  @warn "Both flexbox and float layout systems are enabled. " +
        "This may cause conflicts. Disable one in your configuration.";
}

// Environment-specific warnings
$environment: 'development' !default;

@if $environment == 'production' {
  @if $debug-mode == true {
    @warn "Debug mode is enabled in production environment! " +
          "Set $debug-mode: false for production.";
  }
}

// Warn about large file sizes
@mixin check-utility-classes($count) {
  @if $count > 100 {
    @warn "Generating #{$count} utility classes. " +
          "Consider using a utility framework or PurgeCSS to reduce CSS size.";
  }
}

16.3 @error Directive for Custom Error Messages

Directive Behavior Use Case Impact
@error Stops compilation immediately Critical validation failures Prevents broken output
Required Parameters Validate required arguments Function/mixin safety Better API contracts
Type Validation Ensure correct data types Type safety Catch bugs early
Range Validation Check value boundaries Prevent invalid CSS Guaranteed valid output

Example: Parameter validation with @error

@use 'sass:meta';
@use 'sass:list';

// Validate required parameters
@function calculate-spacing($multiplier) {
  @if $multiplier == null {
    @error "calculate-spacing() requires a $multiplier parameter.";
  }
  
  @return $multiplier * 8px;
}

// Type validation
@mixin text-color($color) {
  @if meta.type-of($color) != 'color' {
    @error "text-color() expects a color, got #{meta.type-of($color)}: #{$color}";
  }
  
  color: $color;
}

// Multiple allowed types
@function parse-size($value) {
  $type: meta.type-of($value);
  
  @if $type != 'number' and $type != 'string' {
    @error "parse-size() expects number or string, got #{$type}: #{$value}";
  }
  
  @return $value;
}

// Enum-like validation
@mixin text-align($align) {
  $valid-values: ('left', 'center', 'right', 'justify');
  
  @if not list.index($valid-values, $align) {
    @error "text-align() expects one of #{$valid-values}, got: #{$align}";
  }
  
  text-align: $align;
}

// Usage that triggers error:
.element {
  @include text-align('middle'); // ❌ Error!
  // Error: text-align() expects one of ("left", "center", "right", "justify"), got: "middle"
}

Example: Range and value validation

@use 'sass:math';

// Range validation
@function clamp-opacity($value) {
  @if meta.type-of($value) != 'number' {
    @error "Opacity must be a number, got: #{$value}";
  }
  
  @if $value < 0 or $value > 1 {
    @error "Opacity must be between 0 and 1, got: #{$value}";
  }
  
  @return $value;
}

// Unit validation
@function validate-spacing($value) {
  @if not math.is-unitless($value) {
    $unit: math.unit($value);
    $valid-units: ('px', 'rem', 'em', '%');
    
    @if not index($valid-units, $unit) {
      @error "Spacing must use px, rem, em, or %, got: #{$unit}";
    }
  }
  
  @return $value;
}

// Positive number validation
@function positive-number($value, $name: 'value') {
  @if meta.type-of($value) != 'number' {
    @error "#{$name} must be a number, got: #{meta.type-of($value)}";
  }
  
  @if $value <= 0 {
    @error "#{$name} must be positive, got: #{$value}";
  }
  
  @return $value;
}

// Grid columns validation
@mixin grid-columns($count) {
  @if $count < 1 or $count > 12 {
    @error "Grid columns must be between 1 and 12, got: #{$count}";
  }
  
  @if $count != math.round($count) {
    @error "Grid columns must be an integer, got: #{$count}";
  }
  
  grid-template-columns: repeat($count, 1fr);
}

Example: Configuration and dependency validation

@use 'sass:map';

// Validate required configuration
$theme-config: () !default;

@function require-config($key) {
  @if not map.has-key($theme-config, $key) {
    @error "Missing required configuration: '#{$key}'. " +
           "Please define $theme-config: (#{$key}: ...) before importing.";
  }
  
  @return map.get($theme-config, $key);
}

// Validate map structure
@function validate-theme($theme) {
  $required-keys: ('primary', 'secondary', 'background', 'text');
  
  @each $key in $required-keys {
    @if not map.has-key($theme, $key) {
      @error "Theme missing required key: '#{$key}'. " +
             "Required keys: #{$required-keys}";
    }
  }
  
  @return $theme;
}

// Validate version compatibility
$sass-version: '1.69.0' !default;

@function check-version($min-version) {
  // Simple version check (in real code, parse properly)
  @if $sass-version < $min-version {
    @error "This library requires Sass #{$min-version} or higher. " +
           "You are using Sass #{$sass-version}. Please upgrade.";
  }
  
  @return true;
}

// Validate mutual exclusivity
@mixin validate-layout-mode($mode) {
  $valid-modes: ('flex', 'grid', 'float');
  
  @if not index($valid-modes, $mode) {
    @error "Invalid layout mode: '#{$mode}'. " +
           "Must be one of: #{$valid-modes}";
  }
}

// Check for circular dependencies
$_importing: () !global;

@mixin check-circular-import($module-name) {
  @if index($_importing, $module-name) {
    @error "Circular import detected: #{$module-name} is already being imported. " +
           "Import stack: #{$_importing}";
  }
  
  $_importing: append($_importing, $module-name) !global;
}

16.4 Stack Trace Reading and Error Resolution

Stack Trace Part Information How to Read Action
Error Message What went wrong First line of output Understand the problem
File Path Where error occurred filename.scss:line:column Navigate to file
Backtrace Call chain Indented list of calls Trace execution path
Source Excerpt Code context Lines around error See actual code
Caret (^) Exact error position Points to character Pinpoint issue

Example: Reading a typical Sass error

// Error output example:
Error: Undefined variable.

3 │   color: $primry-color; // Typo!
  │          ^^^^^^^^^^^^^

  styles.scss 3:10  root stylesheet

// Breaking it down:
// 1. "Undefined variable" - The problem
// 2. Line 3, Column 10 - Exact location
// 3. The caret points to the typo: $primry-color
// 4. Should be: $primary-color

// Resolution:
.button {
  color: $primary-color; // Fixed!
}

Example: Understanding nested stack traces

// Complex error with multiple levels
Error: $color: transparant is not a color.

8background: mix(white, $color, 20%);
  │               ^^^^^^^^^^^^^^^^^^^^^^^

  _functions.scss 8:15  lighten-color()
  _theme.scss 15:12     create-theme()
  main.scss 23:3        root stylesheet

// Reading the stack trace (bottom to top):
// 1. main.scss:23 - Called create-theme()
// 2. _theme.scss:15 - create-theme() called lighten-color()
// 3. _functions.scss:8 - lighten-color() tried to mix colors
// 4. Error: 'transparant' is not a color (typo: should be 'transparent')

// Trace the error path:
// main.scss
@use 'theme';
$my-theme: create-theme('transparant'); // ❌ Typo here!

// _theme.scss
@use 'functions';
@function create-theme($bg) {
  @return lighten-color($bg); // Passes typo to next function
}

// _functions.scss
@function lighten-color($color) {
  @return mix(white, $color, 20%); // ❌ Fails here because $color is invalid
}

// Resolution:
$my-theme: create-theme('transparent'); // ✅ Fixed!

Example: Common error patterns and solutions

// 1. Undefined Variable
// Error: Undefined variable.
$primary: #1976d2;
.button { color: $priamry; } // Typo
// Solution: Fix spelling or import the file with the variable

// 2. Invalid CSS
// Error: Expected expression.
.box {
  width: ; // Missing value
}
// Solution: Provide a value

// 3. Type Error
// Error: $weight: "bold" is not a number.
font-weight: mix(400, "bold", 50%); // Can't mix number and string
// Solution: Use correct types

// 4. Division
// Error: Undefined operation "300px / 16".
font-size: 300px / 16; // Sass doesn't auto-divide
// Solution: Use math.div()
@use 'sass:math';
font-size: math.div(300px, 16);

// 5. Missing Import
// Error: Undefined mixin.
.button { @include flex-center; } // Mixin not imported
// Solution: @use the file containing the mixin

// 6. Circular Import
// Error: Module loop: circular import
// _a.scss imports _b.scss, _b.scss imports _a.scss
// Solution: Refactor to break the cycle

// 7. Invalid Selector
// Error: Invalid CSS after "...": expected selector
.#{$var} {
  .& { } // Can't use & at start
}
// Solution: &.class or .class&

// 8. Map Error
// Error: (primary: #1976d2, secondary: #dc004e) is not a color.
$colors: (primary: #1976d2);
background: $colors; // Trying to use map as color
// Solution: background: map.get($colors, primary);

// 9. Incompatible Units
// Error: Incompatible units px and %.
width: 100px + 50%; // Can't add different units
// Solution: Use calc() or convert units

// 10. @extend Outside
// Error: @extend may only be used within style rules.
@extend %placeholder; // At root level
// Solution: Move inside a selector

16.5 Debugging Tools and Browser Integration

Tool Feature Platform Use Case
Chrome DevTools Source maps, CSS inspector Chrome, Edge Live debugging
Firefox DevTools Style editor, source maps Firefox CSS debugging
Safari Web Inspector Styles pane, sources Safari macOS/iOS debugging
VS Code Debugger Breakpoints in SCSS VS Code Pre-compilation debug
Sass Playground Online compiler Web Quick testing
Source Maps Map CSS to SCSS All browsers Find original source

Example: Chrome DevTools debugging workflow

// 1. Enable source maps in compilation
sass --watch --source-map src/scss:dist/css

// 2. Source SCSS file: src/scss/components/_button.scss
.button {
  $bg: #1976d2;
  $padding: 12px 24px;
  
  background: $bg;
  padding: $padding;
  
  &:hover {
    background: darken($bg, 10%);
  }
}

// 3. In Chrome DevTools:
// - Open DevTools (F12)
// - Navigate to Sources tab
// - Expand "webpack://" or "scss://" folder
// - Find src/scss/components/_button.scss
// - See original SCSS with variables!

// 4. Inspect element shows:
// ┌─────────────────────────────────────┐
// │ Styles                              │
// ├─────────────────────────────────────┤
// │ .button                             │
// │   background: #1976d2;              │
// │   _button.scss:5                    │ ← Click to see SCSS
// │   padding: 12px 24px;               │
// │   _button.scss:6                    │
// └─────────────────────────────────────┘

// 5. Edit SCSS directly (with workspace):
// - Right-click source folder → "Add folder to workspace"
// - Allow access
// - Edit SCSS in DevTools Sources tab
// - Changes save to disk automatically
// - Sass watch mode recompiles
// - Page updates with new styles

// 6. Override styles temporarily:
// - In Elements → Styles pane
// - Add/modify CSS
// - See which SCSS file it came from
// - Update the actual SCSS file

Example: VS Code SCSS debugging setup

// .vscode/tasks.json - Compile task
{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Watch Sass",
      "type": "shell",
      "command": "sass",
      "args": [
        "--watch",
        "--style=expanded",
        "--source-map",
        "src/scss:dist/css"
      ],
      "problemMatcher": ["$sass"],
      "isBackground": true,
      "group": {
        "kind": "build",
        "isDefault": true
      }
    }
  ]
}

// .vscode/launch.json - Debug configuration
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "chrome",
      "request": "launch",
      "name": "Debug in Chrome",
      "url": "http://localhost:3000",
      "webRoot": "${workspaceFolder}",
      "sourceMaps": true,
      "preLaunchTask": "Watch Sass"
    }
  ]
}

// VS Code Extensions for SCSS:
// 1. Sass (.sass) - Syntax highlighting
// 2. SCSS IntelliSense - Autocomplete
// 3. SCSS Formatter - Code formatting
// 4. Live Sass Compiler - Auto-compile with output

// Usage:
// 1. Press Ctrl+Shift+B to start Sass watcher
// 2. Press F5 to launch debugger
// 3. Set breakpoints in JavaScript (not SCSS)
// 4. Inspect styles in integrated browser

Example: Source map debugging techniques

// Generate detailed source maps
sass --watch \
  --embed-sources \
  --source-map \
  --source-map-urls=relative \
  src/scss:dist/css

// Result: main.css.map
{
  "version": 3,
  "sourceRoot": "",
  "sources": [
    "../src/scss/main.scss",
    "../src/scss/_variables.scss",
    "../src/scss/components/_button.scss"
  ],
  "sourcesContent": [
    "@use 'variables';\n@use 'components/button';",
    "$primary: #1976d2;",
    ".button { background: $primary; }"
  ],
  "names": [],
  "mappings": "AAEA;EACE;EACA;;AAEA;EACE"
}

// Browser DevTools features:
// 1. Click CSS property → jumps to SCSS line
// 2. See variable name instead of computed value
// 3. Edit SCSS (with workspaces)
// 4. Search across SCSS files
// 5. Set CSS breakpoints (pause when style applied)

// Debugging without source maps:
// ❌ Elements → Styles shows:
//    main.css:234 { background: #1976d2; }
//    (No way to know which SCSS file)

// ✅ With source maps:
//    _button.scss:12 { background: $primary; }
//    (Shows exact SCSS file and line)

16.6 Common Error Patterns and Solutions

Error Pattern Cause Solution Prevention
Undefined Variable Typo or missing import Check spelling, import file Use linter, IDE autocomplete
Module Not Found Wrong path in @use/@import Verify file path Consistent file structure
Type Mismatch Wrong data type Validate input types Add type checks
Division Error Using / for division Use math.div() Always use math module
Circular Import A imports B, B imports A Refactor architecture One-way dependencies
@extend Outside Rule @extend at root level Move inside selector Use mixins instead

Example: Error prevention patterns

// 1. Defensive function design
@use 'sass:meta';
@use 'sass:math';

@function safe-divide($a, $b, $fallback: 0) {
  // Validate types
  @if meta.type-of($a) != 'number' or meta.type-of($b) != 'number' {
    @warn "safe-divide expects numbers, got: #{$a}, #{$b}";
    @return $fallback;
  }
  
  // Check for zero division
  @if $b == 0 {
    @warn "Division by zero, returning fallback: #{$fallback}";
    @return $fallback;
  }
  
  @return math.div($a, $b);
}

// 2. Null-safe map access
@function get-or-default($map, $key, $default: null) {
  @if not meta.type-of($map) == 'map' {
    @error "Expected map, got: #{meta.type-of($map)}";
  }
  
  @if map.has-key($map, $key) {
    @return map.get($map, $key);
  }
  
  @if $default == null {
    @warn "Key '#{$key}' not found in map and no default provided";
  }
  
  @return $default;
}

// 3. Runtime type checking
@mixin type-safe-property($property, $value, $allowed-types...) {
  $type: meta.type-of($value);
  
  @if not index($allowed-types, $type) {
    @error "#{$property} expects one of #{$allowed-types}, got: #{$type}";
  }
  
  #{$property}: $value;
}

// Usage
.element {
  @include type-safe-property('padding', 20px, 'number');
  @include type-safe-property('color', #000, 'color', 'string');
}

// 4. Import guard pattern
$_module-loaded: false !default;

@if $_module-loaded {
  @error "This module has already been loaded. Avoid importing it multiple times.";
}

$_module-loaded: true !global;

// 5. Version compatibility check
@if not function-exists('math.div') {
  @error "This code requires Sass 1.33.0 or higher for math.div(). " +
         "Please upgrade your Sass version.";
}

Example: Debugging helpers library

// _debug.scss - Reusable debugging utilities
@use 'sass:meta';
@use 'sass:map';
@use 'sass:list';

// Visual debugging overlay
@mixin debug-outline($color: red) {
  outline: 2px solid $color !important;
  outline-offset: -2px;
}

// Show all elements
@mixin debug-all($color: rgba(255, 0, 0, 0.2)) {
  * {
    @include debug-outline($color);
  }
}

// Print variable with formatting
@mixin debug-var($name, $value) {
  @debug "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━";
  @debug "Variable: #{$name}";
  @debug "  Type: #{meta.type-of($value)}";
  @debug "  Value: #{$value}";
  
  @if meta.type-of($value) == 'map' {
    @debug "  Keys: #{map.keys($value)}";
  } @else if meta.type-of($value) == 'list' {
    @debug "  Length: #{list.length($value)}";
  }
  @debug "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━";
}

// Performance timing
$_debug-timers: () !default;

@mixin start-timer($name) {
  // In real implementation, use timestamp
  @debug "[TIMER] Started: #{$name}";
}

@mixin end-timer($name) {
  @debug "[TIMER] Ended: #{$name}";
}

// Assertion helper
@mixin assert-equals($actual, $expected, $message: '') {
  @if $actual != $expected {
    @error "Assertion failed: #{$message}\n" +
           "  Expected: #{$expected}\n" +
           "  Actual: #{$actual}";
  } @else {
    @debug "✓ Assertion passed: #{$message}";
  }
}

// Usage examples
$primary: #1976d2;
@include debug-var('Primary Color', $primary);

@include start-timer('compilation');
// ... your code ...
@include end-timer('compilation');

@include assert-equals(10px + 5px, 15px, 'Basic math');

Example: Error recovery strategies

// Graceful degradation
@function get-color($theme, $key) {
  // Try to get from theme
  @if map.has-key($theme, $key) {
    @return map.get($theme, $key);
  }
  
  // Fallback to default colors
  @warn "Color '#{$key}' not found in theme, using default";
  
  $defaults: (
    primary: #1976d2,
    secondary: #dc004e,
    background: #ffffff,
    text: #000000
  );
  
  @if map.has-key($defaults, $key) {
    @return map.get($defaults, $key);
  }
  
  // Last resort
  @error "Color '#{$key}' not found in theme or defaults";
}

// Try-catch pattern (error suppression)
@function try-parse-number($value) {
  @if meta.type-of($value) == 'number' {
    @return $value;
  }
  
  // Try to parse string to number
  @if meta.type-of($value) == 'string' {
    @if str-index($value, 'px') {
      // In real implementation, parse the number
      @warn "String contains px, attempting conversion";
      @return 0px; // Placeholder
    }
  }
  
  @warn "Cannot parse '#{$value}' as number, returning 0";
  @return 0;
}

// Validation with auto-correction
@function validate-spacing($value) {
  // Must be positive
  @if $value < 0 {
    @warn "Spacing cannot be negative (#{$value}), using absolute value";
    @return abs($value);
  }
  
  // Warn about large values
  @if $value > 100px {
    @warn "Unusually large spacing value: #{$value}";
  }
  
  @return $value;
}

// Progressive enhancement
@mixin with-fallback($property, $modern-value, $fallback-value) {
  #{$property}: $fallback-value; // Fallback first
  
  @supports (#{$property}: #{$modern-value}) {
    #{$property}: $modern-value; // Modern override
  }
}

// Usage
.element {
  @include with-fallback(
    'display',
    'grid',
    'block'
  );
}

Error Handling Best Practices

  • @debug: Use for development logging and inspecting values
  • @warn: Use for deprecations and non-critical issues
  • @error: Use for critical failures that should stop compilation
  • Validate early: Check types and ranges at function entry
  • Meaningful messages: Include context, expected values, and solutions
  • Source maps: Essential for production debugging - map CSS back to SCSS
  • Stack traces: Read bottom-to-top to trace error origin
  • Defensive coding: Add guards, defaults, and null checks
Note: Enable source maps in development and staging environments for effective debugging. In production, disable them unless you need to debug live issues, as they expose your source code structure.

17. CSS Grid and Flexbox Integration

17.1 Grid Template Generation with Loops

Pattern Technique Output Use Case
Column Classes @for loop generation .col-1 through .col-12 Grid systems
Dynamic Templates Interpolation in templates repeat(#{$cols}, 1fr) Responsive grids
Gap Utilities Map iteration .gap-1, .gap-2, etc. Spacing system
Area Templates String building Named grid areas Complex layouts
Auto-fit/fill Mixin generation Responsive columns Flexible layouts

Example: Generate grid column classes

// Basic grid system (12 columns)
@for $i from 1 through 12 {
  .col-#{$i} {
    grid-column: span $i;
  }
}

// Output:
// .col-1 { grid-column: span 1; }
// .col-2 { grid-column: span 2; }
// ...
// .col-12 { grid-column: span 12; }

// Row span classes
@for $i from 1 through 6 {
  .row-#{$i} {
    grid-row: span $i;
  }
}

// Column start positions
@for $i from 1 through 12 {
  .col-start-#{$i} {
    grid-column-start: $i;
  }
  
  .col-end-#{$i} {
    grid-column-end: $i;
  }
}

// Grid template variations
@for $cols from 1 through 6 {
  .grid-cols-#{$cols} {
    grid-template-columns: repeat($cols, 1fr);
  }
}

// Output:
// .grid-cols-1 { grid-template-columns: repeat(1, 1fr); }
// .grid-cols-2 { grid-template-columns: repeat(2, 1fr); }
// .grid-cols-3 { grid-template-columns: repeat(3, 1fr); }
// ...

Example: Advanced grid template generation

// Gap utilities with spacing scale
$spacing-scale: (
  0: 0,
  1: 0.25rem,
  2: 0.5rem,
  3: 0.75rem,
  4: 1rem,
  5: 1.25rem,
  6: 1.5rem,
  8: 2rem,
  10: 2.5rem,
  12: 3rem,
  16: 4rem
);

@each $key, $value in $spacing-scale {
  .gap-#{$key} {
    gap: $value;
  }
  
  .gap-x-#{$key} {
    column-gap: $value;
  }
  
  .gap-y-#{$key} {
    row-gap: $value;
  }
}

// Responsive grid templates
$breakpoints: (
  sm: 640px,
  md: 768px,
  lg: 1024px,
  xl: 1280px
);

@each $name, $size in $breakpoints {
  @media (min-width: $size) {
    @for $cols from 1 through 12 {
      .#{$name}\:grid-cols-#{$cols} {
        grid-template-columns: repeat($cols, 1fr);
      }
      
      .#{$name}\:col-span-#{$cols} {
        grid-column: span $cols;
      }
    }
  }
}

// Usage:
// <div class="grid-cols-1 md:grid-cols-2 lg:grid-cols-3">

Example: Complex grid area templates

// Grid area template builder
@mixin grid-areas($areas...) {
  $template: '';
  
  @each $row in $areas {
    $template: $template + '"#{$row}" ';
  }
  
  grid-template-areas: #{$template};
}

// Usage
.layout {
  display: grid;
  grid-template-columns: 200px 1fr 200px;
  grid-template-rows: auto 1fr auto;
  
  @include grid-areas(
    'header header header',
    'sidebar main aside',
    'footer footer footer'
  );
}

// Named grid lines
@mixin grid-lines($count: 12) {
  $columns: ();
  
  @for $i from 1 through $count + 1 {
    $columns: append($columns, '[col-#{$i}] 1fr', comma);
  }
  
  grid-template-columns: $columns;
}

.grid-with-lines {
  display: grid;
  @include grid-lines(12);
}

// Generates:
// grid-template-columns: [col-1] 1fr [col-2] 1fr ... [col-13] 1fr;

// Dynamic grid based on item count
@mixin auto-grid($min-width: 250px, $max-cols: 4) {
  display: grid;
  grid-template-columns: repeat(
    auto-fit,
    minmax(min($min-width, 100%), 1fr)
  );
  gap: 1rem;
}

.card-grid {
  @include auto-grid(300px);
}

17.2 Flexbox Utility Mixins and Functions

Mixin Properties Use Case Example
flex-center justify + align center Center content Modal, cards
flex-between justify space-between Headers, toolbars Logo + nav
flex-column flex-direction column Vertical layouts Sidebars
flex-wrap flex-wrap + gap Tag clouds Chip lists
flex-grow Dynamic flex values Flexible sizing Form layouts

Example: Comprehensive flexbox utility library

// Basic flex mixins
@mixin flex-center {
  display: flex;
  justify-content: center;
  align-items: center;
}

@mixin flex-between {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

@mixin flex-around {
  display: flex;
  justify-content: space-around;
  align-items: center;
}

@mixin flex-evenly {
  display: flex;
  justify-content: space-evenly;
  align-items: center;
}

@mixin flex-start {
  display: flex;
  justify-content: flex-start;
  align-items: center;
}

@mixin flex-end {
  display: flex;
  justify-content: flex-end;
  align-items: center;
}

// Column layouts
@mixin flex-column($gap: 0) {
  display: flex;
  flex-direction: column;
  @if $gap != 0 {
    gap: $gap;
  }
}

@mixin flex-column-center {
  @include flex-column;
  align-items: center;
  justify-content: center;
}

// Configurable flex
@mixin flex(
  $direction: row,
  $justify: flex-start,
  $align: stretch,
  $wrap: nowrap,
  $gap: 0
) {
  display: flex;
  flex-direction: $direction;
  justify-content: $justify;
  align-items: $align;
  flex-wrap: $wrap;
  
  @if $gap != 0 {
    gap: $gap;
  }
}

// Usage
.header {
  @include flex-between;
}

.card-content {
  @include flex-column(1rem);
}

.toolbar {
  @include flex(row, space-between, center, nowrap, 0.5rem);
}

Example: Advanced flexbox patterns

// Flex item utilities
@mixin flex-item($grow: 0, $shrink: 1, $basis: auto) {
  flex: $grow $shrink $basis;
}

@mixin flex-grow($value: 1) {
  flex-grow: $value;
  flex-shrink: 1;
  flex-basis: 0;
}

@mixin flex-shrink($value: 1) {
  flex-shrink: $value;
}

@mixin flex-none {
  flex: none; // Don't grow or shrink
}

// Holy grail layout
@mixin flex-holy-grail($sidebar-width: 250px) {
  display: flex;
  
  .sidebar {
    @include flex-none;
    width: $sidebar-width;
  }
  
  .main {
    @include flex-grow;
  }
}

// Flex wrap with gap fallback
@mixin flex-wrap($gap: 1rem) {
  display: flex;
  flex-wrap: wrap;
  
  // Modern: use gap
  gap: $gap;
  
  // Fallback for older browsers
  @supports not (gap: $gap) {
    margin: calc(-#{$gap} / 2);
    
    > * {
      margin: calc(#{$gap} / 2);
    }
  }
}

// Responsive flex direction
@mixin flex-responsive(
  $mobile-direction: column,
  $desktop-direction: row,
  $breakpoint: 768px
) {
  display: flex;
  flex-direction: $mobile-direction;
  
  @media (min-width: $breakpoint) {
    flex-direction: $desktop-direction;
  }
}

// Usage
.card-list {
  @include flex-wrap(1.5rem);
}

.feature-section {
  @include flex-responsive(column, row, 768px);
}

// Equal height columns
@mixin flex-equal-height {
  display: flex;
  
  > * {
    display: flex;
    flex-direction: column;
    flex: 1 1 0; // Equal width, equal height
  }
}

Example: Flexbox utility class generator

// Generate flex utility classes
$flex-properties: (
  'justify': (
    'start': flex-start,
    'end': flex-end,
    'center': center,
    'between': space-between,
    'around': space-around,
    'evenly': space-evenly
  ),
  'align': (
    'start': flex-start,
    'end': flex-end,
    'center': center,
    'stretch': stretch,
    'baseline': baseline
  ),
  'direction': (
    'row': row,
    'row-reverse': row-reverse,
    'col': column,
    'col-reverse': column-reverse
  ),
  'wrap': (
    'wrap': wrap,
    'nowrap': nowrap,
    'wrap-reverse': wrap-reverse
  )
);

@each $prop, $variants in $flex-properties {
  @each $name, $value in $variants {
    .#{$prop}-#{$name} {
      @if $prop == 'justify' {
        justify-content: $value;
      } @else if $prop == 'align' {
        align-items: $value;
      } @else if $prop == 'direction' {
        flex-direction: $value;
      } @else if $prop == 'wrap' {
        flex-wrap: $value;
      }
    }
  }
}

// Flex grow/shrink classes
@for $i from 0 through 12 {
  .flex-grow-#{$i} {
    flex-grow: $i;
  }
  
  .flex-shrink-#{$i} {
    flex-shrink: $i;
  }
}

// Output:
// .justify-start { justify-content: flex-start; }
// .justify-center { justify-content: center; }
// .align-center { align-items: center; }
// .direction-row { flex-direction: row; }
// .flex-grow-1 { flex-grow: 1; }
// etc.

17.3 Layout Component Mixins

Component Layout Type Features Use Case
Card Grid CSS Grid auto-fit Responsive columns Product listings
Sidebar Layout Grid template areas Named regions Admin dashboards
Stack Flexbox column + gap Vertical spacing Form fields
Cluster Flexbox wrap + gap Dynamic wrapping Tags, badges
Split Flexbox space-between Push items apart Headers
Center Grid place-items Perfect centering Modals, heroes

Example: Essential layout component mixins

// Stack - Vertical spacing
@mixin stack($gap: 1rem, $split-after: null) {
  display: flex;
  flex-direction: column;
  gap: $gap;
  
  @if $split-after {
    > :nth-child(#{$split-after}) {
      margin-bottom: auto;
    }
  }
}

// Cluster - Horizontal wrapping with gap
@mixin cluster($gap: 1rem, $justify: flex-start, $align: center) {
  display: flex;
  flex-wrap: wrap;
  gap: $gap;
  justify-content: $justify;
  align-items: $align;
}

// Sidebar - Fixed sidebar + flexible content
@mixin sidebar(
  $sidebar-width: 250px,
  $gap: 1rem,
  $side: left
) {
  display: grid;
  gap: $gap;
  
  @if $side == left {
    grid-template-columns: $sidebar-width 1fr;
  } @else {
    grid-template-columns: 1fr $sidebar-width;
  }
  
  @media (max-width: 768px) {
    grid-template-columns: 1fr;
  }
}

// Switcher - Switch from row to column at threshold
@mixin switcher($threshold: 768px, $gap: 1rem, $limit: 4) {
  display: flex;
  flex-wrap: wrap;
  gap: $gap;
  
  > * {
    flex-grow: 1;
    flex-basis: calc((#{$threshold} - 100%) * 999);
  }
  
  @if $limit {
    > :nth-last-child(n + #{$limit + 1}),
    > :nth-last-child(n + #{$limit + 1}) ~ * {
      flex-basis: 100%;
    }
  }
}

// Cover - Centered content with header/footer
@mixin cover($gap: 1rem, $min-height: 100vh) {
  display: flex;
  flex-direction: column;
  min-height: $min-height;
  gap: $gap;
  
  > * {
    margin-block: 0;
  }
  
  > :first-child:not(.center) {
    margin-block-start: 0;
  }
  
  > :last-child:not(.center) {
    margin-block-end: 0;
  }
  
  > .center {
    margin-block: auto;
  }
}

// Usage
.tags {
  @include cluster(0.5rem, flex-start, center);
}

.dashboard {
  @include sidebar(300px, 2rem, left);
}

.card-stack {
  @include stack(1.5rem);
}

.hero {
  @include cover(2rem, 100vh);
}

Example: Grid-based layout components

// Auto-fit grid with minimum card width
@mixin auto-grid(
  $min-width: 250px,
  $gap: 1rem,
  $max-cols: null
) {
  display: grid;
  gap: $gap;
  
  @if $max-cols {
    grid-template-columns: repeat(
      auto-fit,
      minmax(min($min-width, 100%), 1fr)
    );
    
    // Limit maximum columns
    @supports (width: min($min-width, 100%)) {
      grid-template-columns: repeat(
        auto-fit,
        minmax(min(#{$min-width}, calc(100% / #{$max-cols})), 1fr)
      );
    }
  } @else {
    grid-template-columns: repeat(
      auto-fit,
      minmax(min($min-width, 100%), 1fr)
    );
  }
}

// Reel - Horizontal scrolling container
@mixin reel($item-width: 300px, $gap: 1rem) {
  display: flex;
  gap: $gap;
  overflow-x: auto;
  overflow-y: hidden;
  
  // Snap scroll
  scroll-snap-type: x mandatory;
  scroll-padding: $gap;
  
  > * {
    flex: 0 0 $item-width;
    scroll-snap-align: start;
  }
  
  // Hide scrollbar
  scrollbar-width: none;
  &::-webkit-scrollbar {
    display: none;
  }
}

// Imposter - Centered overlay
@mixin imposter($fixed: false) {
  @if $fixed {
    position: fixed;
  } @else {
    position: absolute;
  }
  
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

// Frame - Aspect ratio container
@mixin frame($ratio: 16/9) {
  aspect-ratio: $ratio;
  overflow: hidden;
  display: flex;
  justify-content: center;
  align-items: center;
  
  // Fallback for browsers without aspect-ratio
  @supports not (aspect-ratio: $ratio) {
    position: relative;
    padding-bottom: calc(100% / (#{$ratio}));
    
    > * {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
    }
  }
}

// Usage
.product-grid {
  @include auto-grid(280px, 1.5rem, 4);
}

.carousel {
  @include reel(350px, 1rem);
}

.video-container {
  @include frame(16/9);
}

.modal-overlay {
  @include imposter(fixed);
}

Example: Complex layout patterns

// Holy Grail layout with header and footer
@mixin holy-grail(
  $sidebar-width: 250px,
  $aside-width: 200px,
  $gap: 1rem
) {
  display: grid;
  grid-template-columns: $sidebar-width 1fr $aside-width;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header header header"
    "sidebar main aside"
    "footer footer footer";
  gap: $gap;
  min-height: 100vh;
  
  .header { grid-area: header; }
  .sidebar { grid-area: sidebar; }
  .main { grid-area: main; }
  .aside { grid-area: aside; }
  .footer { grid-area: footer; }
  
  @media (max-width: 1024px) {
    grid-template-columns: $sidebar-width 1fr;
    grid-template-areas:
      "header header"
      "sidebar main"
      "footer footer";
    
    .aside {
      display: none;
    }
  }
  
  @media (max-width: 768px) {
    grid-template-columns: 1fr;
    grid-template-areas:
      "header"
      "main"
      "footer";
    
    .sidebar {
      display: none;
    }
  }
}

// Pancake stack - Header/Content/Footer
@mixin pancake-stack {
  display: grid;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
}

// 12-column grid system
@mixin twelve-column-grid($gap: 1rem) {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: $gap;
  
  // Span helpers
  @for $i from 1 through 12 {
    .span-#{$i} {
      grid-column: span $i;
    }
  }
}

// Masonry-like layout (column approach)
@mixin masonry($columns: 3, $gap: 1rem) {
  column-count: $columns;
  column-gap: $gap;
  
  > * {
    break-inside: avoid;
    margin-bottom: $gap;
  }
  
  @media (max-width: 1024px) {
    column-count: $columns - 1;
  }
  
  @media (max-width: 768px) {
    column-count: 1;
  }
}

// Usage
.app-layout {
  @include holy-grail(280px, 220px, 1.5rem);
}

.page {
  @include pancake-stack;
}

.gallery {
  @include masonry(4, 1rem);
}

17.4 Responsive Layout Patterns

Pattern Technique Behavior Best For
RAM Pattern repeat(auto-fit, minmax()) Auto-responsive columns Card grids
Flex Wrap flex-wrap with flex-basis Natural wrapping Navigation, tags
Container Query @container rule Component-aware layout Reusable components
Grid Template Areas Named areas + media queries Layout reorganization Complex pages
Clamp Width clamp() for fluid sizing Self-adjusting Fluid typography, spacing

Example: Responsive auto-grid (RAM pattern)

// RAM = Repeat, Auto-fit, Minmax
@mixin responsive-grid(
  $min: 250px,
  $max: 1fr,
  $gap: 1rem
) {
  display: grid;
  grid-template-columns: repeat(
    auto-fit,
    minmax(min($min, 100%), $max)
  );
  gap: $gap;
}

// With breakpoint override
@mixin responsive-grid-breakpoint(
  $min: 250px,
  $gap: 1rem,
  $mobile-cols: 1,
  $tablet-cols: 2,
  $desktop-cols: null
) {
  display: grid;
  gap: $gap;
  
  // Mobile
  grid-template-columns: repeat($mobile-cols, 1fr);
  
  // Tablet
  @media (min-width: 640px) {
    grid-template-columns: repeat($tablet-cols, 1fr);
  }
  
  // Desktop - use auto-fit
  @media (min-width: 1024px) {
    @if $desktop-cols {
      grid-template-columns: repeat($desktop-cols, 1fr);
    } @else {
      grid-template-columns: repeat(
        auto-fit,
        minmax(min($min, 100%), 1fr)
      );
    }
  }
}

// Flexible columns based on content
@mixin intrinsic-grid($min: 200px, $gap: 1rem) {
  display: grid;
  grid-template-columns: repeat(
    auto-fit,
    minmax($min, max-content)
  );
  gap: $gap;
  justify-content: start;
}

// Usage
.product-grid {
  @include responsive-grid(280px, 1fr, 1.5rem);
}

.feature-cards {
  @include responsive-grid-breakpoint(300px, 2rem, 1, 2, 3);
}

.tag-cloud {
  @include intrinsic-grid(100px, 0.5rem);
}

Example: Responsive flex patterns

// Flex that switches to column on mobile
@mixin responsive-flex(
  $breakpoint: 768px,
  $gap: 1rem,
  $mobile-gap: null
) {
  display: flex;
  gap: $gap;
  
  @media (max-width: $breakpoint - 1) {
    flex-direction: column;
    
    @if $mobile-gap {
      gap: $mobile-gap;
    }
  }
}

// Equal-width items that stack on mobile
@mixin equal-flex-items($items: 3, $breakpoint: 768px, $gap: 1rem) {
  display: flex;
  flex-wrap: wrap;
  gap: $gap;
  
  > * {
    flex: 1 1 calc((100% / #{$items}) - #{$gap});
    min-width: calc((100% / #{$items}) - #{$gap});
  }
  
  @media (max-width: $breakpoint) {
    > * {
      flex: 1 1 100%;
      min-width: 100%;
    }
  }
}

// Flex with minimum item width
@mixin flex-responsive-items(
  $min-width: 250px,
  $gap: 1rem
) {
  display: flex;
  flex-wrap: wrap;
  gap: $gap;
  
  > * {
    flex: 1 1 $min-width;
    max-width: 100%;
  }
}

// Priority sidebar (sidebar collapses first)
@mixin priority-sidebar(
  $sidebar-width: 300px,
  $content-min: 60%,
  $gap: 1rem
) {
  display: flex;
  gap: $gap;
  flex-wrap: wrap;
  
  .sidebar {
    flex: 1 1 $sidebar-width;
  }
  
  .content {
    flex: 999 1 $content-min;
    min-width: $content-min;
  }
}

// Usage
.hero-content {
  @include responsive-flex(768px, 2rem, 1rem);
}

.feature-row {
  @include equal-flex-items(3, 768px, 1.5rem);
}

.layout {
  @include priority-sidebar(280px, 65%, 2rem);
}

Example: Grid template area reorganization

// Responsive grid areas
@mixin responsive-areas(
  $desktop-areas,
  $desktop-cols,
  $desktop-rows,
  $tablet-areas: null,
  $tablet-cols: null,
  $tablet-rows: null,
  $mobile-areas: null,
  $gap: 1rem
) {
  display: grid;
  gap: $gap;
  
  // Desktop (default)
  grid-template-columns: $desktop-cols;
  grid-template-rows: $desktop-rows;
  grid-template-areas: $desktop-areas;
  
  // Tablet
  @if $tablet-areas {
    @media (max-width: 1024px) {
      grid-template-columns: $tablet-cols;
      grid-template-rows: $tablet-rows;
      grid-template-areas: $tablet-areas;
    }
  }
  
  // Mobile
  @if $mobile-areas {
    @media (max-width: 768px) {
      grid-template-columns: 1fr;
      grid-template-areas: $mobile-areas;
    }
  }
}

// Dashboard layout example
.dashboard {
  @include responsive-areas(
    // Desktop: 3 columns
    $desktop-areas: 
      "header header header"
      "nav main aside"
      "nav main aside"
      "footer footer footer",
    $desktop-cols: 200px 1fr 250px,
    $desktop-rows: auto 1fr auto auto,
    
    // Tablet: 2 columns
    $tablet-areas:
      "header header"
      "nav main"
      "nav main"
      "footer footer",
    $tablet-cols: 180px 1fr,
    $tablet-rows: auto 1fr auto auto,
    
    // Mobile: 1 column
    $mobile-areas:
      "header"
      "main"
      "footer",
    $gap: 1.5rem
  );
  
  .header { grid-area: header; }
  .nav { grid-area: nav; }
  .main { grid-area: main; }
  .aside { grid-area: aside; }
  .footer { grid-area: footer; }
  
  // Hide aside on tablet and mobile
  @media (max-width: 1024px) {
    .aside { display: none; }
  }
  
  // Hide nav on mobile
  @media (max-width: 768px) {
    .nav { display: none; }
  }
}

17.5 CSS Subgrid and Advanced Grid Features

Feature Syntax Browser Support Use Case
Subgrid grid-template: subgrid Modern browsers Modern Nested grids aligned to parent
Grid Auto-flow grid-auto-flow: dense All modern Good Fill gaps automatically
Min/Max Content min-content, max-content All modern Good Intrinsic sizing
Fit-content fit-content(max) All modern Good Clamp to content size
Minmax minmax(min, max) All modern Good Flexible sizing with bounds

Example: CSS Subgrid implementation

// Subgrid for aligned nested content
@mixin card-grid-subgrid($columns: 3, $gap: 1rem) {
  display: grid;
  grid-template-columns: repeat($columns, 1fr);
  gap: $gap;
  
  .card {
    display: grid;
    grid-template-rows: subgrid;
    grid-row: span 3; // header, content, footer
    
    .card-header { grid-row: 1; }
    .card-content { grid-row: 2; }
    .card-footer { grid-row: 3; }
  }
}

// Subgrid with fallback
@mixin subgrid-columns($fallback-template: 1fr) {
  display: grid;
  
  // Fallback for browsers without subgrid
  grid-template-columns: $fallback-template;
  
  // Subgrid for supported browsers
  @supports (grid-template-columns: subgrid) {
    grid-template-columns: subgrid;
  }
}

// Example usage
.product-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  grid-auto-rows: auto auto auto;
  gap: 2rem;
  
  .product {
    display: grid;
    grid-row: span 3;
    
    @supports (grid-template-rows: subgrid) {
      grid-template-rows: subgrid;
      
      // All product images align
      .product-image { grid-row: 1; }
      // All titles align
      .product-title { grid-row: 2; }
      // All prices align
      .product-price { grid-row: 3; }
    }
    
    // Fallback
    @supports not (grid-template-rows: subgrid) {
      grid-template-rows: auto 1fr auto;
    }
  }
}

Example: Advanced grid techniques

// Dense packing with auto-flow
@mixin masonry-grid($columns: 4, $gap: 1rem) {
  display: grid;
  grid-template-columns: repeat($columns, 1fr);
  grid-auto-rows: 10px; // Small row size
  grid-auto-flow: dense; // Fill gaps
  gap: $gap;
  
  > * {
    // Items span based on content height
    grid-row: span var(--row-span, 10);
  }
}

// Intrinsic sizing with min/max-content
@mixin intrinsic-columns {
  display: grid;
  grid-template-columns:
    min-content    // Smallest possible
    max-content    // Largest needed
    fit-content(300px) // Clamp at 300px
    1fr;           // Flexible
  gap: 1rem;
}

// Complex minmax patterns
@mixin flexible-grid(
  $min: 200px,
  $max: 1fr,
  $count: auto-fit
) {
  display: grid;
  grid-template-columns: repeat(
    $count,
    minmax(min($min, 100%), $max)
  );
  gap: 1rem;
}

// Grid with auto-placement and spanning
@mixin featured-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  grid-auto-rows: 200px;
  gap: 1rem;
  
  // Featured items span 2x2
  .featured {
    grid-column: span 2;
    grid-row: span 2;
  }
  
  // Wide items span 2 columns
  .wide {
    grid-column: span 2;
  }
  
  // Tall items span 2 rows
  .tall {
    grid-row: span 2;
  }
}

// Named lines for precise control
@mixin grid-with-named-lines {
  display: grid;
  grid-template-columns:
    [full-start] 1fr
    [content-start] minmax(0, 1200px)
    [content-end] 1fr
    [full-end];
  
  // Full-width items
  .full-width {
    grid-column: full;
  }
  
  // Content-constrained items
  .content {
    grid-column: content;
  }
}

// Usage
.gallery {
  @include masonry-grid(4, 1.5rem);
}

.pinterest-layout {
  @include featured-grid;
}

.page-wrapper {
  @include grid-with-named-lines;
}

Example: Complex grid patterns

// Asymmetric grid layout
@mixin asymmetric-grid {
  display: grid;
  grid-template-columns:
    2fr     // Main content (larger)
    1fr;    // Sidebar (smaller)
  grid-template-rows:
    auto    // Header
    1fr     // Content (flexible)
    auto;   // Footer
  gap: 2rem;
  min-height: 100vh;
}

// Magazine-style grid
@mixin magazine-layout {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  grid-auto-rows: 100px;
  gap: 1rem;
  
  .hero {
    grid-column: 1 / span 8;
    grid-row: 1 / span 3;
  }
  
  .featured {
    grid-column: 9 / span 4;
    grid-row: 1 / span 2;
  }
  
  .sidebar {
    grid-column: 9 / span 4;
    grid-row: 3 / span 1;
  }
  
  .articles {
    grid-column: 1 / span 8;
    grid-row: 4 / span 2;
    
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 1rem;
  }
}

// Overlapping grid items
@mixin overlap-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  grid-template-rows: repeat(4, 100px);
  
  .background {
    grid-column: 1 / -1;
    grid-row: 1 / -1;
    z-index: 0;
  }
  
  .content {
    grid-column: 2 / 6;
    grid-row: 2 / 4;
    z-index: 1;
  }
}

// Grid with implicit tracks
@mixin auto-grid-rows($min-height: 200px) {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  grid-auto-rows: minmax($min-height, auto);
  gap: 1rem;
}

17.6 Container Queries and Intrinsic Layouts

Feature Syntax Benefit Use Case
Container Type container-type: inline-size Component-aware Reusable components
Container Query @container (min-width: 400px) Context-based styling Adaptive cards
Named Containers container-name: sidebar Specific targeting Multiple containers
Container Units cqw, cqh, cqi, cqb Relative to container Fluid sizing
Intrinsic Sizing width: fit-content Content-based size Dynamic layouts

Example: Container query patterns

// Basic container setup
@mixin container($name: null, $type: inline-size) {
  container-type: $type;
  
  @if $name {
    container-name: $name;
  }
}

// Responsive card with container queries
@mixin responsive-card {
  @include container(card);
  
  .card-content {
    display: flex;
    flex-direction: column;
    gap: 1rem;
  }
  
  // When container is wide enough, use row layout
  @container (min-width: 400px) {
    .card-content {
      flex-direction: row;
      align-items: center;
    }
    
    .card-image {
      width: 40%;
    }
    
    .card-text {
      width: 60%;
    }
  }
  
  // Even wider, use different layout
  @container (min-width: 600px) {
    .card-content {
      display: grid;
      grid-template-columns: 200px 1fr;
      gap: 2rem;
    }
  }
}

// Named container queries
.sidebar {
  @include container(sidebar, inline-size);
  
  .widget {
    // Query specific container
    @container sidebar (min-width: 300px) {
      display: grid;
      grid-template-columns: 1fr 1fr;
    }
  }
}

// Container query units
.adaptive-text {
  @include container;
  
  h2 {
    // Font size relative to container width
    font-size: clamp(1.5rem, 5cqw, 3rem);
  }
  
  .description {
    // Padding relative to container
    padding: 2cqi; // 2% of inline size
  }
}

Example: Container query component library

// Mixin for container-aware components
@mixin container-component($name, $breakpoints) {
  container-name: $name;
  container-type: inline-size;
  
  @each $size, $width in $breakpoints {
    @container #{$name} (min-width: #{$width}) {
      @content($size);
    }
  }
}

// Usage
.product-card {
  @include container-component(
    product,
    (small: 300px, medium: 500px, large: 700px)
  ) using ($size) {
    @if $size == small {
      .product-image {
        aspect-ratio: 1;
      }
    } @else if $size == medium {
      display: grid;
      grid-template-columns: 200px 1fr;
      
      .product-image {
        aspect-ratio: 3/4;
      }
    } @else if $size == large {
      grid-template-columns: 300px 1fr 200px;
      
      .product-actions {
        display: block;
      }
    }
  }
}

// Container query with fallback
@mixin container-with-fallback($width) {
  // Fallback using media query
  @media (min-width: $width) {
    @content;
  }
  
  // Progressive enhancement with container query
  @supports (container-type: inline-size) {
    @media (min-width: 0) {
      @content; // Reset media query
    }
    
    @container (min-width: $width) {
      @content;
    }
  }
}

// Container-aware grid
@mixin container-grid {
  container-type: inline-size;
  display: grid;
  gap: 1rem;
  
  // Compact layout (default)
  grid-template-columns: 1fr;
  
  // Medium container
  @container (min-width: 400px) {
    grid-template-columns: repeat(2, 1fr);
  }
  
  // Large container
  @container (min-width: 700px) {
    grid-template-columns: repeat(3, 1fr);
  }
  
  // Extra large container
  @container (min-width: 1000px) {
    grid-template-columns: repeat(4, 1fr);
  }
}

Example: Intrinsic sizing patterns

// Intrinsic centering
@mixin intrinsic-center($max-width: none) {
  width: fit-content;
  margin-inline: auto;
  
  @if $max-width != none {
    max-width: $max-width;
  }
}

// Intrinsic sidebar
@mixin intrinsic-sidebar(
  $sidebar-min: 200px,
  $content-min: 60%
) {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  
  .sidebar {
    flex-basis: $sidebar-min;
    flex-grow: 1;
  }
  
  .content {
    flex-basis: 0;
    flex-grow: 999;
    min-width: $content-min;
  }
}

// Quantity queries (style based on item count)
@mixin quantity-query($min, $max: null) {
  @if $max {
    // Between min and max items
    &:nth-last-child(n + #{$min}):nth-last-child(-n + #{$max}),
    &:nth-last-child(n + #{$min}):nth-last-child(-n + #{$max}) ~ & {
      @content;
    }
  } @else {
    // At least min items
    &:nth-last-child(n + #{$min}),
    &:nth-last-child(n + #{$min}) ~ & {
      @content;
    }
  }
}

// Auto-sizing grid
@mixin auto-size-grid($min: 250px) {
  display: grid;
  grid-template-columns: repeat(
    auto-fit,
    minmax(min($min, 100%), 1fr)
  );
  gap: 1rem;
  
  // Items adjust based on available space
  > * {
    width: 100%;
    height: 100%;
  }
}

// Usage
.centered-form {
  @include intrinsic-center(600px);
}

.layout {
  @include intrinsic-sidebar(280px, 65%);
}

// Style differently based on number of items
.nav-item {
  @include quantity-query(5) {
    // When 5+ items, reduce font size
    font-size: 0.875rem;
  }
}

.photo-grid {
  @include auto-size-grid(300px);
}

Grid and Flexbox Integration Summary

  • Grid for 2D layouts: Use CSS Grid for complex, two-dimensional layouts
  • Flex for 1D layouts: Use Flexbox for one-dimensional, flexible content flow
  • Auto-fit/fill: Create responsive grids without media queries
  • Subgrid: Align nested grid items to parent grid (modern browsers)
  • Container queries: Style components based on their container size, not viewport
  • Layout mixins: Stack, Cluster, Sidebar patterns for common layouts
  • Intrinsic sizing: Use fit-content, min-content for content-aware layouts
  • Combine techniques: Grid + Flex together for optimal layouts
Note: Container queries with @container enable component-level responsiveness, making components truly reusable regardless of where they're placed. Always set container-type on the parent element.

18. Animation and Keyframe Generation

18.1 Keyframe Mixins and Animation Libraries

Pattern Technique Output Use Case
Keyframe Mixin @mixin with @keyframes Reusable animations Common effects
Animation Shorthand Single-line animation setup Quick application Simple animations
Animation Library Pre-built animation set Ready-to-use effects Rapid development
Prefix Handling Vendor prefix automation Cross-browser support Legacy browsers
Composable Animations Combine multiple effects Complex movements Rich interactions

Example: Basic keyframe animation mixins

// Reusable keyframe mixin
@mixin keyframes($name) {
  @keyframes #{$name} {
    @content;
  }
}

// Usage - Fade in animation
@include keyframes(fadeIn) {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

// Slide in from left
@include keyframes(slideInLeft) {
  from {
    transform: translateX(-100%);
    opacity: 0;
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

// Bounce effect
@include keyframes(bounce) {
  0%, 20%, 50%, 80%, 100% {
    transform: translateY(0);
  }
  40% {
    transform: translateY(-30px);
  }
  60% {
    transform: translateY(-15px);
  }
}

// Apply animation
.element {
  animation: fadeIn 0.5s ease-out;
}

.slide {
  animation: slideInLeft 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}

.bouncing {
  animation: bounce 1s infinite;
}

Example: Animation library with mixin helpers

// Animation application mixin
@mixin animate(
  $name,
  $duration: 0.3s,
  $timing: ease,
  $delay: 0s,
  $iteration: 1,
  $direction: normal,
  $fill: both
) {
  animation-name: $name;
  animation-duration: $duration;
  animation-timing-function: $timing;
  animation-delay: $delay;
  animation-iteration-count: $iteration;
  animation-direction: $direction;
  animation-fill-mode: $fill;
}

// Shorthand animation
@mixin anim($name, $duration: 0.3s, $timing: ease) {
  animation: $name $duration $timing;
}

// Fade animations
@include keyframes(fadeIn) {
  from { opacity: 0; }
  to { opacity: 1; }
}

@include keyframes(fadeOut) {
  from { opacity: 1; }
  to { opacity: 0; }
}

@include keyframes(fadeInUp) {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@include keyframes(fadeInDown) {
  from {
    opacity: 0;
    transform: translateY(-20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

// Scale animations
@include keyframes(zoomIn) {
  from {
    opacity: 0;
    transform: scale(0.3);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

@include keyframes(pulse) {
  0%, 100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.05);
  }
}

// Rotation animations
@include keyframes(rotate) {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

@include keyframes(shake) {
  0%, 100% { transform: translateX(0); }
  10%, 30%, 50%, 70%, 90% { transform: translateX(-10px); }
  20%, 40%, 60%, 80% { transform: translateX(10px); }
}

// Usage
.modal {
  @include animate(fadeInUp, 0.4s, cubic-bezier(0.4, 0, 0.2, 1));
}

.loader {
  @include anim(rotate, 1s, linear);
  animation-iteration-count: infinite;
}

.error-message {
  @include anim(shake, 0.5s, ease-in-out);
}

Example: Advanced animation library patterns

// Configurable entrance animations
@mixin entrance-animation(
  $name,
  $from-opacity: 0,
  $from-transform: translateY(20px),
  $to-opacity: 1,
  $to-transform: translateY(0)
) {
  @include keyframes($name) {
    from {
      opacity: $from-opacity;
      transform: $from-transform;
    }
    to {
      opacity: $to-opacity;
      transform: $to-transform;
    }
  }
}

// Generate entrance variations
@include entrance-animation('enterFromBottom', 0, translateY(50px));
@include entrance-animation('enterFromTop', 0, translateY(-50px));
@include entrance-animation('enterFromLeft', 0, translateX(-50px));
@include entrance-animation('enterFromRight', 0, translateX(50px));

// Attention seekers
@include keyframes(heartbeat) {
  0%, 100% {
    transform: scale(1);
  }
  10%, 30% {
    transform: scale(0.9);
  }
  20%, 40% {
    transform: scale(1.1);
  }
}

@include keyframes(wiggle) {
  0%, 100% { transform: rotate(0deg); }
  25% { transform: rotate(-5deg); }
  75% { transform: rotate(5deg); }
}

@include keyframes(flash) {
  0%, 50%, 100% { opacity: 1; }
  25%, 75% { opacity: 0; }
}

// Loading animations
@include keyframes(spin) {
  to { transform: rotate(360deg); }
}

@include keyframes(dots) {
  0%, 20% { content: '.'; }
  40% { content: '..'; }
  60%, 100% { content: '...'; }
}

// Utility mixin for animation delays
@mixin stagger-animation($base-delay: 0.1s, $count: 5) {
  @for $i from 1 through $count {
    &:nth-child(#{$i}) {
      animation-delay: $base-delay * ($i - 1);
    }
  }
}

// Usage
.list-item {
  @include anim(fadeInUp, 0.4s, ease-out);
  @include stagger-animation(0.1s, 10);
}

18.2 Dynamic Animation Generation with Maps

Technique Data Structure Benefit Use Case
Map-based Config Animation properties map Centralized settings Consistent animations
Loop Generation @each over animation map Auto-generate variants Multiple animations
Timing Presets Easing function map Reusable timing Brand consistency
Duration Scale Speed multiplier map Consistent timing Animation speeds
State Animations State-to-animation map Logical mapping UI state changes

Example: Map-based animation system

// Animation configuration map
$animations: (
  'fade-in': (
    from: (opacity: 0),
    to: (opacity: 1),
    duration: 0.3s,
    timing: ease-out
  ),
  'slide-up': (
    from: (opacity: 0, transform: translateY(20px)),
    to: (opacity: 1, transform: translateY(0)),
    duration: 0.4s,
    timing: cubic-bezier(0.4, 0, 0.2, 1)
  ),
  'scale-in': (
    from: (opacity: 0, transform: scale(0.8)),
    to: (opacity: 1, transform: scale(1)),
    duration: 0.35s,
    timing: cubic-bezier(0.34, 1.56, 0.64, 1)
  ),
  'rotate-in': (
    from: (opacity: 0, transform: rotate(-180deg) scale(0.5)),
    to: (opacity: 1, transform: rotate(0deg) scale(1)),
    duration: 0.6s,
    timing: ease-out
  )
);

// Generate keyframes from map
@each $name, $config in $animations {
  @include keyframes($name) {
    from {
      @each $prop, $value in map-get($config, from) {
        #{$prop}: $value;
      }
    }
    to {
      @each $prop, $value in map-get($config, to) {
        #{$prop}: $value;
      }
    }
  }
  
  // Generate utility class
  .animate-#{$name} {
    animation: $name 
      map-get($config, duration)
      map-get($config, timing);
  }
}

// Output:
// @keyframes fade-in { ... }
// .animate-fade-in { animation: fade-in 0.3s ease-out; }
// @keyframes slide-up { ... }
// .animate-slide-up { animation: slide-up 0.4s cubic-bezier(...); }
// etc.

Example: Timing function and duration scales

// Easing function library
$easings: (
  'linear': linear,
  'ease': ease,
  'ease-in': ease-in,
  'ease-out': ease-out,
  'ease-in-out': ease-in-out,
  'ease-in-quad': cubic-bezier(0.55, 0.085, 0.68, 0.53),
  'ease-out-quad': cubic-bezier(0.25, 0.46, 0.45, 0.94),
  'ease-in-cubic': cubic-bezier(0.55, 0.055, 0.675, 0.19),
  'ease-out-cubic': cubic-bezier(0.215, 0.61, 0.355, 1),
  'ease-in-quart': cubic-bezier(0.895, 0.03, 0.685, 0.22),
  'ease-out-quart': cubic-bezier(0.165, 0.84, 0.44, 1),
  'ease-in-back': cubic-bezier(0.6, -0.28, 0.735, 0.045),
  'ease-out-back': cubic-bezier(0.175, 0.885, 0.32, 1.275),
  'ease-in-out-back': cubic-bezier(0.68, -0.55, 0.265, 1.55)
);

// Duration scale
$durations: (
  'instant': 0.1s,
  'fast': 0.2s,
  'normal': 0.3s,
  'slow': 0.5s,
  'slower': 0.8s,
  'slowest': 1.2s
);

// Helper function to get easing
@function ease($name) {
  @return map-get($easings, $name);
}

// Helper function to get duration
@function duration($name) {
  @return map-get($durations, $name);
}

// Animation mixin using presets
@mixin preset-animate($name, $duration-key: 'normal', $easing-key: 'ease-out') {
  animation: $name duration($duration-key) ease($easing-key);
}

// Generate timing utility classes
@each $name, $value in $easings {
  .ease-#{$name} {
    animation-timing-function: $value;
  }
}

@each $name, $value in $durations {
  .duration-#{$name} {
    animation-duration: $value;
  }
}

// Usage
.modal {
  @include preset-animate(fadeIn, 'normal', 'ease-out-back');
}

.notification {
  animation: slideInRight duration('fast') ease('ease-out-quad');
}

// HTML usage:
// <div class="animate-fade-in duration-slow ease-ease-out-back">

Example: Complex animation sequences with maps

// Multi-step animation configuration
$complex-animations: (
  'loading-pulse': (
    steps: (
      0: (transform: scale(1), opacity: 1),
      50: (transform: scale(1.2), opacity: 0.7),
      100: (transform: scale(1), opacity: 1)
    ),
    duration: 1.5s,
    timing: ease-in-out,
    iteration: infinite
  ),
  'success-check': (
    steps: (
      0: (transform: scale(0) rotate(0deg), opacity: 0),
      50: (transform: scale(1.2) rotate(360deg), opacity: 1),
      100: (transform: scale(1) rotate(360deg), opacity: 1)
    ),
    duration: 0.6s,
    timing: cubic-bezier(0.68, -0.55, 0.265, 1.55),
    iteration: 1
  ),
  'error-shake': (
    steps: (
      0: (transform: translateX(0)),
      10: (transform: translateX(-10px)),
      20: (transform: translateX(10px)),
      30: (transform: translateX(-10px)),
      40: (transform: translateX(10px)),
      50: (transform: translateX(-10px)),
      60: (transform: translateX(10px)),
      70: (transform: translateX(-10px)),
      80: (transform: translateX(10px)),
      90: (transform: translateX(-10px)),
      100: (transform: translateX(0))
    ),
    duration: 0.8s,
    timing: ease,
    iteration: 1
  )
);

// Generate complex keyframes
@each $name, $config in $complex-animations {
  @include keyframes($name) {
    @each $percent, $properties in map-get($config, steps) {
      #{$percent}% {
        @each $prop, $value in $properties {
          #{$prop}: $value;
        }
      }
    }
  }
  
  .#{$name} {
    animation-name: $name;
    animation-duration: map-get($config, duration);
    animation-timing-function: map-get($config, timing);
    animation-iteration-count: map-get($config, iteration);
  }
}

18.3 CSS Transition Mixins and Timing Functions

Mixin Properties Use Case Example
transition Single property transition Simple effects Button hover
transitions Multiple properties Complex changes Card expand
transition-all All properties Quick prototyping Theme changes
Custom easing Cubic bezier curves Brand feel Material Design
Hardware acceleration transform, opacity Performance Smooth animations

Example: Transition utility mixins

// Single property transition
@mixin transition($property, $duration: 0.3s, $timing: ease, $delay: 0s) {
  transition: $property $duration $timing $delay;
}

// Multiple property transitions
@mixin transitions($transitions...) {
  transition: $transitions;
}

// Transition all properties
@mixin transition-all($duration: 0.3s, $timing: ease) {
  transition: all $duration $timing;
}

// No transition
@mixin no-transition {
  transition: none !important;
}

// Hardware-accelerated properties only
@mixin hw-transition($duration: 0.3s, $timing: ease) {
  transition: transform $duration $timing,
              opacity $duration $timing;
}

// Usage examples
.button {
  @include transition(background-color, 0.2s, ease-out);
  
  &:hover {
    background-color: darken(#1976d2, 10%);
  }
}

.card {
  @include transitions(
    transform 0.3s cubic-bezier(0.4, 0, 0.2, 1),
    box-shadow 0.3s ease-out,
    background-color 0.2s ease
  );
  
  &:hover {
    transform: translateY(-4px);
    box-shadow: 0 8px 16px rgba(0,0,0,0.2);
  }
}

.modal {
  @include hw-transition(0.4s, cubic-bezier(0.4, 0, 0.2, 1));
}

// Disable transitions for reduced motion
@media (prefers-reduced-motion: reduce) {
  * {
    @include no-transition;
    animation-duration: 0.01ms !important;
  }
}

Example: Timing function library with presets

// Timing function presets
$timing-functions: (
  // Standard
  'linear': linear,
  'ease': ease,
  'ease-in': ease-in,
  'ease-out': ease-out,
  'ease-in-out': ease-in-out,
  
  // Material Design
  'material-standard': cubic-bezier(0.4, 0, 0.2, 1),
  'material-decelerate': cubic-bezier(0, 0, 0.2, 1),
  'material-accelerate': cubic-bezier(0.4, 0, 1, 1),
  'material-sharp': cubic-bezier(0.4, 0, 0.6, 1),
  
  // Expressive
  'bounce': cubic-bezier(0.68, -0.55, 0.265, 1.55),
  'elastic': cubic-bezier(0.68, -0.6, 0.32, 1.6),
  'overshoot': cubic-bezier(0.175, 0.885, 0.32, 1.275),
  
  // Smooth
  'smooth': cubic-bezier(0.25, 0.1, 0.25, 1),
  'smooth-in': cubic-bezier(0.42, 0, 1, 1),
  'smooth-out': cubic-bezier(0, 0, 0.58, 1),
  'smooth-in-out': cubic-bezier(0.42, 0, 0.58, 1)
);

// Get timing function
@function timing($name) {
  @if map-has-key($timing-functions, $name) {
    @return map-get($timing-functions, $name);
  }
  @warn "Timing function '#{$name}' not found.";
  @return ease;
}

// Transition with preset timing
@mixin t($property, $duration: 0.3s, $timing-name: 'ease-out', $delay: 0s) {
  transition: $property $duration timing($timing-name) $delay;
}

// Generate timing utility classes
@each $name, $function in $timing-functions {
  .timing-#{$name} {
    transition-timing-function: $function;
  }
}

// Usage
.button {
  @include t(all, 0.2s, 'material-standard');
}

.dropdown {
  @include t(opacity, 0.15s, 'material-decelerate');
  @include t(transform, 0.3s, 'material-decelerate');
}

.notification {
  transition: transform 0.4s timing('bounce'),
              opacity 0.3s timing('ease-out');
}

Example: Advanced transition patterns

// Stagger transition delays
@mixin stagger-transition(
  $property: all,
  $duration: 0.3s,
  $timing: ease-out,
  $base-delay: 0.05s,
  $count: 10
) {
  transition: $property $duration $timing;
  
  @for $i from 1 through $count {
    &:nth-child(#{$i}) {
      transition-delay: $base-delay * ($i - 1);
    }
  }
}

// Conditional transitions (only specific properties)
@mixin transition-props($props, $duration: 0.3s, $timing: ease) {
  $transition-list: ();
  
  @each $prop in $props {
    $transition-list: append($transition-list, $prop $duration $timing, comma);
  }
  
  transition: $transition-list;
}

// Safe transitions (avoid layout thrashing)
@mixin safe-transition($duration: 0.3s, $timing: ease) {
  // Only transition properties that don't trigger layout
  transition: transform $duration $timing,
              opacity $duration $timing,
              color $duration $timing,
              background-color $duration $timing,
              border-color $duration $timing,
              box-shadow $duration $timing;
}

// Transition with will-change optimization
@mixin optimized-transition($property, $duration: 0.3s, $timing: ease) {
  will-change: $property;
  transition: $property $duration $timing;
  
  &:hover,
  &:focus {
    will-change: auto;
  }
}

// Usage
.list-item {
  @include stagger-transition(transform, 0.3s, ease-out, 0.05s, 20);
}

.card {
  @include transition-props((transform, box-shadow), 0.3s, ease-out);
}

.menu-item {
  @include safe-transition(0.2s, ease-out);
}

.hero-image {
  @include optimized-transition(transform, 0.6s, ease-out);
}

18.4 Transform Function Utilities

Transform Function Use Case Performance
translate translateX/Y/Z Movement GPU accelerated Fast
scale scaleX/Y/Z Zoom effects GPU accelerated Fast
rotate rotateX/Y/Z Rotation GPU accelerated Fast
skew skewX/Y Distortion GPU accelerated Fast
3D transforms translate3d, etc. Depth effects Hardware accelerated Fast

Example: Transform utility mixins

// Center with transform
@mixin center-transform {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

// Center horizontally
@mixin center-x {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
}

// Center vertically
@mixin center-y {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
}

// Hardware acceleration hint
@mixin hardware-accelerate {
  transform: translateZ(0);
  backface-visibility: hidden;
  perspective: 1000px;
}

// 3D card flip
@mixin card-flip($duration: 0.6s) {
  transform-style: preserve-3d;
  transition: transform $duration;
  
  .front,
  .back {
    backface-visibility: hidden;
    position: absolute;
    width: 100%;
    height: 100%;
  }
  
  .back {
    transform: rotateY(180deg);
  }
  
  &.flipped {
    transform: rotateY(180deg);
  }
}

// Parallax effect
@mixin parallax($speed: 0.5) {
  transform: translateY(calc(var(--scroll) * #{$speed}px));
}

// Usage
.modal-content {
  @include center-transform;
}

.dropdown-menu {
  @include center-x;
  top: 100%;
}

.card {
  @include hardware-accelerate;
  
  &:hover {
    transform: translateY(-4px) translateZ(0);
  }
}

.flip-card {
  @include card-flip(0.6s);
}

.parallax-bg {
  @include parallax(0.3);
}

Example: Complex transform combinations

// Transform builder function
@function build-transform($transforms...) {
  $result: '';
  
  @each $transform in $transforms {
    $result: $result + ' ' + $transform;
  }
  
  @return unquote($result);
}

// Common transform combinations
@mixin lift($distance: 8px, $scale: 1.02) {
  transform: translateY(-#{$distance}) scale($scale);
}

@mixin push($distance: 2px) {
  transform: translateY($distance) scale(0.98);
}

@mixin swing {
  transform-origin: top center;
  @include keyframes(swing) {
    20% { transform: rotate(15deg); }
    40% { transform: rotate(-10deg); }
    60% { transform: rotate(5deg); }
    80% { transform: rotate(-5deg); }
    100% { transform: rotate(0deg); }
  }
}

@mixin wobble {
  @include keyframes(wobble) {
    0%, 100% { transform: translateX(0) rotate(0); }
    15% { transform: translateX(-25px) rotate(-5deg); }
    30% { transform: translateX(20px) rotate(3deg); }
    45% { transform: translateX(-15px) rotate(-3deg); }
    60% { transform: translateX(10px) rotate(2deg); }
    75% { transform: translateX(-5px) rotate(-1deg); }
  }
}

// 3D transforms
@mixin rotate-3d($x: 0, $y: 1, $z: 0, $angle: 45deg) {
  transform: rotate3d($x, $y, $z, $angle);
}

@mixin flip-horizontal {
  transform: scaleX(-1);
}

@mixin flip-vertical {
  transform: scaleY(-1);
}

// Perspective helper
@mixin perspective($distance: 1000px) {
  perspective: $distance;
  perspective-origin: center;
}

// Usage
.card {
  transition: transform 0.3s ease-out;
  
  &:hover {
    @include lift(10px, 1.05);
  }
  
  &:active {
    @include push(4px);
  }
}

.badge {
  animation: swing 1s ease-in-out;
}

.container-3d {
  @include perspective(1200px);
  
  .item {
    @include rotate-3d(1, 0, 0, 15deg);
  }
}

.mirrored {
  @include flip-horizontal;
}

Example: Transform animation sequences

// Entrance animations with transforms
@mixin slide-enter($from: left, $distance: 100%, $duration: 0.4s) {
  @if $from == left {
    @include keyframes(slideEnterLeft) {
      from { transform: translateX(-#{$distance}); opacity: 0; }
      to { transform: translateX(0); opacity: 1; }
    }
    animation: slideEnterLeft $duration ease-out;
  } @else if $from == right {
    @include keyframes(slideEnterRight) {
      from { transform: translateX($distance); opacity: 0; }
      to { transform: translateX(0); opacity: 1; }
    }
    animation: slideEnterRight $duration ease-out;
  } @else if $from == top {
    @include keyframes(slideEnterTop) {
      from { transform: translateY(-#{$distance}); opacity: 0; }
      to { transform: translateY(0); opacity: 1; }
    }
    animation: slideEnterTop $duration ease-out;
  } @else if $from == bottom {
    @include keyframes(slideEnterBottom) {
      from { transform: translateY($distance); opacity: 0; }
      to { transform: translateY(0); opacity: 1; }
    }
    animation: slideEnterBottom $duration ease-out;
  }
}

// Scale entrance
@mixin scale-enter($from: 0.8, $duration: 0.3s, $timing: ease-out) {
  @include keyframes(scaleEnter) {
    from {
      transform: scale($from);
      opacity: 0;
    }
    to {
      transform: scale(1);
      opacity: 1;
    }
  }
  animation: scaleEnter $duration $timing;
}

// Rotate entrance
@mixin rotate-enter($degrees: 90deg, $duration: 0.5s) {
  @include keyframes(rotateEnter) {
    from {
      transform: rotate($degrees) scale(0.5);
      opacity: 0;
    }
    to {
      transform: rotate(0deg) scale(1);
      opacity: 1;
    }
  }
  animation: rotateEnter $duration cubic-bezier(0.68, -0.55, 0.265, 1.55);
}

// Usage
.sidebar {
  @include slide-enter(left, 300px, 0.4s);
}

.modal {
  @include scale-enter(0.7, 0.3s, cubic-bezier(0.34, 1.56, 0.64, 1));
}

.notification {
  @include rotate-enter(180deg, 0.6s);
}

18.5 Animation State Management

State CSS Property Control Use Case
Play/Pause animation-play-state paused/running User control
Direction animation-direction normal/reverse/alternate Reversible animations
Fill Mode animation-fill-mode forwards/backwards/both End state retention
Iteration animation-iteration-count number/infinite Looping control
Delay animation-delay Time value Sequence timing

Example: Animation state control mixins

// Pause animation on hover
@mixin pause-on-hover {
  &:hover {
    animation-play-state: paused;
  }
}

// Play animation on hover
@mixin play-on-hover($name, $duration: 1s, $timing: ease) {
  animation: $name $duration $timing paused;
  
  &:hover {
    animation-play-state: running;
  }
}

// Reverse on second hover
@mixin reverse-on-second-hover($name, $duration: 0.5s) {
  animation: $name $duration ease-out;
  animation-fill-mode: both;
  
  &.reversed {
    animation-direction: reverse;
  }
}

// Animation with state classes
@mixin stateful-animation(
  $name,
  $duration: 0.5s,
  $timing: ease
) {
  animation: $name $duration $timing;
  animation-fill-mode: both;
  animation-play-state: paused;
  
  &.playing {
    animation-play-state: running;
  }
  
  &.reverse {
    animation-direction: reverse;
  }
  
  &.loop {
    animation-iteration-count: infinite;
  }
}

// Sequential animations
@mixin sequence($animations...) {
  $total-duration: 0s;
  
  @each $anim in $animations {
    $name: nth($anim, 1);
    $duration: nth($anim, 2);
    $delay: $total-duration;
    
    &.step-#{index($animations, $anim)} {
      animation: $name $duration ease-out $delay;
      animation-fill-mode: both;
    }
    
    $total-duration: $total-duration + $duration;
  }
}

// Usage
.spinner {
  @include pause-on-hover;
}

.icon {
  @include play-on-hover(bounce, 0.6s, ease-in-out);
}

.menu {
  @include stateful-animation(slideDown, 0.4s, ease-out);
}

// JavaScript adds/removes classes:
// element.classList.add('playing');
// element.classList.add('reverse');
// element.classList.add('loop');

Example: Animation orchestration

// Chain animations using animation-delay
@mixin animation-chain($animations) {
  $total-delay: 0s;
  $all-animations: ();
  
  @each $name, $duration in $animations {
    $all-animations: append(
      $all-animations,
      $name $duration ease-out $total-delay both,
      comma
    );
    $total-delay: $total-delay + $duration;
  }
  
  animation: $all-animations;
}

// Staggered group animation
@mixin stagger-group(
  $animation,
  $duration: 0.3s,
  $delay: 0.1s,
  $count: 10
) {
  animation: $animation $duration ease-out;
  animation-fill-mode: both;
  
  @for $i from 1 through $count {
    &:nth-child(#{$i}) {
      animation-delay: ($i - 1) * $delay;
    }
  }
}

// Coordinated entrance
@mixin coordinated-entrance($children-map) {
  @each $selector, $config in $children-map {
    #{$selector} {
      animation: map-get($config, animation)
                 map-get($config, duration)
                 map-get($config, timing)
                 map-get($config, delay);
      animation-fill-mode: both;
    }
  }
}

// Usage - Chain multiple animations
.logo {
  @include animation-chain((
    fadeIn: 0.5s,
    slideUp: 0.4s,
    bounce: 0.6s
  ));
}

// Staggered list items
.nav-item {
  @include stagger-group(fadeInLeft, 0.4s, 0.08s, 8);
}

// Coordinated page entrance
.hero {
  @include coordinated-entrance((
    '.hero-title': (
      animation: fadeInUp,
      duration: 0.6s,
      timing: ease-out,
      delay: 0.2s
    ),
    '.hero-subtitle': (
      animation: fadeInUp,
      duration: 0.6s,
      timing: ease-out,
      delay: 0.4s
    ),
    '.hero-cta': (
      animation: scaleIn,
      duration: 0.5s,
      timing: cubic-bezier(0.68, -0.55, 0.265, 1.55),
      delay: 0.8s
    )
  ));
}

Example: Event-driven animation states

// Loading state animations
@mixin loading-state($animation: pulse) {
  &.loading {
    animation: $animation 1.5s ease-in-out infinite;
    pointer-events: none;
    
    & > * {
      opacity: 0.6;
    }
  }
}

// Success/error state transitions
@mixin result-states {
  transition: all 0.3s ease-out;
  
  &.success {
    animation: successPulse 0.6s ease-out;
    background-color: #4caf50;
    color: white;
  }
  
  &.error {
    animation: errorShake 0.5s ease-in-out;
    background-color: #f44336;
    color: white;
  }
}

// Define state animations
@include keyframes(successPulse) {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.05); }
}

@include keyframes(errorShake) {
  0%, 100% { transform: translateX(0); }
  10%, 30%, 50%, 70%, 90% { transform: translateX(-8px); }
  20%, 40%, 60%, 80% { transform: translateX(8px); }
}

// Focus/blur animations
@mixin focus-animation($scale: 1.02) {
  transition: transform 0.2s ease-out;
  
  &:focus {
    transform: scale($scale);
    outline: 2px solid #2196f3;
    outline-offset: 2px;
  }
}

// Hover intent (delayed hover)
@mixin hover-intent($delay: 0.3s) {
  &:hover {
    animation: hoverIntent $delay ease-out;
    animation-fill-mode: forwards;
  }
  
  @include keyframes(hoverIntent) {
    from { opacity: 1; }
    to { opacity: 1; transform: translateY(-4px); }
  }
}

// Usage
.submit-button {
  @include loading-state(rotate);
  @include result-states;
}

.input-field {
  @include focus-animation(1.02);
}

.card {
  @include hover-intent(0.2s);
}

18.6 Performance-optimized Animation Patterns

Technique Implementation Benefit Impact
GPU Acceleration transform, opacity only 60fps animations Smooth performance
will-change Hint to browser Pre-optimization Faster start
contain Isolation hint Limit repaints Better performance
Reduced Motion prefers-reduced-motion Accessibility Better UX
Layer Promotion translateZ(0) Own composite layer Isolated rendering

Example: GPU-accelerated animations

// Force GPU acceleration
@mixin gpu-accelerate {
  transform: translateZ(0);
  backface-visibility: hidden;
  perspective: 1000px;
  will-change: transform;
}

// Performant transform animation
@mixin performant-transform($property: transform, $duration: 0.3s) {
  @include gpu-accelerate;
  transition: $property $duration cubic-bezier(0.4, 0, 0.2, 1);
}

// Only animate GPU-friendly properties
@mixin gpu-animation {
  // ✅ GOOD: transform and opacity (GPU accelerated)
  transition: transform 0.3s ease-out,
              opacity 0.3s ease-out;
  
  // ❌ AVOID: width, height, top, left (trigger layout)
  // transition: width 0.3s, height 0.3s, top 0.3s;
}

// Layer promotion for animations
@mixin promote-layer {
  will-change: transform, opacity;
  
  // Remove after animation
  &.animated {
    will-change: auto;
  }
}

// Composite layer for smooth animations
@mixin composite-layer {
  // Create new stacking context
  position: relative;
  z-index: 0;
  
  // Promote to own layer
  transform: translateZ(0);
  
  // Contain paint and layout
  contain: layout paint;
}

// Usage
.smooth-card {
  @include performant-transform(transform, 0.4s);
  
  &:hover {
    transform: translateY(-8px) scale(1.02);
  }
}

.modal {
  @include composite-layer;
  @include gpu-animation;
}

Example: Accessibility and reduced motion

// Respect user's motion preferences
@mixin respect-motion-preference {
  @media (prefers-reduced-motion: reduce) {
    animation: none !important;
    transition: none !important;
  }
}

// Safe animation (automatically disabled for reduced motion)
@mixin safe-animate(
  $name,
  $duration: 0.3s,
  $timing: ease,
  $fallback-transition: opacity 0.1s
) {
  animation: $name $duration $timing;
  
  @media (prefers-reduced-motion: reduce) {
    animation: none;
    transition: $fallback-transition;
  }
}

// Crossfade instead of movement
@mixin reduced-motion-friendly($normal-anim, $reduced-anim: fadeIn) {
  animation: $normal-anim;
  
  @media (prefers-reduced-motion: reduce) {
    animation: $reduced-anim 0.2s ease-out;
  }
}

// Conditional animation
@mixin motion-safe($animation, $duration: 0.3s) {
  @media (prefers-reduced-motion: no-preference) {
    animation: $animation $duration ease-out;
  }
}

// Global reduced motion reset
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

// Usage
.card {
  @include safe-animate(slideInUp, 0.4s, ease-out, opacity 0.2s);
}

.notification {
  @include reduced-motion-friendly(slideInRight, fadeIn);
}

.hero {
  @include motion-safe(fadeInUp, 0.6s);
}

Example: Performance monitoring and optimization

// Optimized animation helper
@mixin optimized-animation(
  $name,
  $duration: 0.3s,
  $timing: ease-out,
  $will-change-props: transform opacity
) {
  // Enable will-change before animation
  will-change: $will-change-props;
  animation: $name $duration $timing;
  
  // Cleanup after animation
  animation-fill-mode: both;
}

// Debounced animation (prevent too-frequent triggers)
@mixin debounced-animation($name, $duration: 0.3s, $delay: 0.1s) {
  animation: $name $duration ease-out;
  animation-delay: $delay;
  animation-fill-mode: both;
}

// Budget-aware animations (simple on low-end devices)
@mixin progressive-animation(
  $simple-animation,
  $complex-animation,
  $duration: 0.4s
) {
  // Default: simple animation
  animation: $simple-animation $duration ease-out;
  
  // Enhanced on powerful devices (no standard query yet, pseudo-code)
  @supports (backdrop-filter: blur(10px)) {
    animation: $complex-animation $duration cubic-bezier(0.68, -0.55, 0.265, 1.55);
  }
}

// Limit animation complexity based on number of elements
@mixin scale-animation-complexity($threshold: 20) {
  animation: complexAnimation 0.6s ease-out;
  
  // Simplify if many elements
  &:nth-child(n + #{$threshold}) {
    animation: simpleAnimation 0.3s ease-out;
  }
}

// Container-based performance hints
@mixin contained-animation {
  // Limit repaints to element
  contain: layout style paint;
  
  // Isolate rendering
  isolation: isolate;
  
  // Create stacking context
  position: relative;
  z-index: 0;
}

// Usage
.hero-image {
  @include optimized-animation(zoomIn, 0.8s, ease-out, transform opacity);
}

.tooltip {
  @include debounced-animation(fadeIn, 0.2s, 0.3s);
}

.product-card {
  @include progressive-animation(fadeIn, rotateInWithBounce, 0.5s);
}

.animated-list-item {
  @include scale-animation-complexity(50);
}

.animation-container {
  @include contained-animation;
}

Animation Best Practices

  • Use transform and opacity: GPU-accelerated properties for 60fps animations
  • Avoid layout thrashing: Don't animate width, height, top, left, margin, padding
  • will-change sparingly: Use only when needed, remove after animation
  • Respect reduced motion: Always provide @media (prefers-reduced-motion) fallbacks
  • Keep it short: Animations under 500ms feel snappier; avoid long durations
  • Ease-out for entrances: ease-in for exits, ease-in-out for transitions
  • Stagger for groups: Use delays for sequential animations in lists
  • Hardware acceleration: Use translateZ(0) for smooth performance
Note: Always test animations on lower-end devices. Use transform and opacity exclusively for 60fps performance. Provide meaningful motion with prefers-reduced-motion support for accessibility.

19. Framework and Library Integration

19.1 Bootstrap SCSS Customization

Feature Customization Method File/Variable Impact
Theme Colors Override $theme-colors map _variables.scss Primary, secondary, etc.
Grid System Configure breakpoints/columns $grid-breakpoints Responsive layout
Typography Font family/size variables $font-family-base Global text styles
Spacing Scale $spacer variable margin/padding utilities Consistent spacing
Component Imports Selective @import bootstrap.scss Reduced bundle size

Example: Bootstrap customization setup

// custom-bootstrap.scss

// 1. Override default variables BEFORE importing Bootstrap
$primary: #007bff;
$secondary: #6c757d;
$success: #28a745;
$danger: #dc3545;
$warning: #ffc107;
$info: #17a2b8;

// Override theme colors map
$theme-colors: (
  "primary": $primary,
  "secondary": $secondary,
  "success": $success,
  "danger": $danger,
  "warning": $warning,
  "info": $info,
  "light": #f8f9fa,
  "dark": #343a40,
  "custom": #5a67d8  // Add custom color
);

// Grid customization
$grid-breakpoints: (
  xs: 0,
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px,
  xxl: 1400px
);

$container-max-widths: (
  sm: 540px,
  md: 720px,
  lg: 960px,
  xl: 1140px,
  xxl: 1320px
);

// Typography
$font-family-sans-serif: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
$font-size-base: 1rem;
$line-height-base: 1.5;

// Spacing
$spacer: 1rem;
$spacers: (
  0: 0,
  1: $spacer * 0.25,
  2: $spacer * 0.5,
  3: $spacer,
  4: $spacer * 1.5,
  5: $spacer * 3,
  6: $spacer * 4,  // Custom
  7: $spacer * 5   // Custom
);

// Border radius
$border-radius: 0.375rem;
$border-radius-sm: 0.25rem;
$border-radius-lg: 0.5rem;

// 2. Import Bootstrap
@import "~bootstrap/scss/bootstrap";

// 3. Add custom extensions AFTER Bootstrap
.btn-custom {
  @include button-variant($custom, darken($custom, 7.5%));
}

// Custom utilities
.bg-gradient-primary {
  background: linear-gradient(135deg, $primary, darken($primary, 15%));
}

Example: Selective Bootstrap imports for smaller bundles

// minimal-bootstrap.scss

// 1. Include functions first (required)
@import "~bootstrap/scss/functions";

// 2. Include variable overrides
$primary: #007bff;
$enable-shadows: true;
$enable-gradients: false;

// 3. Include required Bootstrap files
@import "~bootstrap/scss/variables";
@import "~bootstrap/scss/mixins";
@import "~bootstrap/scss/root";

// 4. Include only needed components (selective imports)
@import "~bootstrap/scss/reboot";
@import "~bootstrap/scss/type";
@import "~bootstrap/scss/grid";
@import "~bootstrap/scss/containers";
@import "~bootstrap/scss/buttons";
@import "~bootstrap/scss/forms";
@import "~bootstrap/scss/utilities";

// Skip components you don't need:
// @import "~bootstrap/scss/dropdown";
// @import "~bootstrap/scss/modal";
// @import "~bootstrap/scss/carousel";
// @import "~bootstrap/scss/spinners";
// etc.

// 5. Include utilities API (for custom utilities)
@import "~bootstrap/scss/utilities/api";

// 6. Custom utilities
$utilities: map-merge(
  $utilities,
  (
    "cursor": (
      property: cursor,
      class: cursor,
      values: pointer grab grabbing not-allowed
    ),
    "opacity": (
      property: opacity,
      values: (
        0: 0,
        25: .25,
        50: .5,
        75: .75,
        100: 1
      )
    )
  )
);

Example: Advanced Bootstrap customization patterns

// advanced-bootstrap-custom.scss

// Custom color system
$custom-colors: (
  "brand-blue": #0d6efd,
  "brand-purple": #6f42c1,
  "brand-pink": #d63384,
  "brand-orange": #fd7e14
);

// Merge custom colors with theme colors
$theme-colors: map-merge($theme-colors, $custom-colors);

// Generate color variants
@each $color, $value in $theme-colors {
  .bg-#{$color}-subtle {
    background-color: rgba($value, 0.1);
  }
  
  .border-#{$color}-subtle {
    border-color: rgba($value, 0.3);
  }
  
  .text-#{$color}-dark {
    color: darken($value, 15%);
  }
}

// Custom button sizes
$btn-padding-y-xs: 0.125rem;
$btn-padding-x-xs: 0.5rem;
$btn-font-size-xs: 0.75rem;

.btn-xs {
  @include button-size(
    $btn-padding-y-xs,
    $btn-padding-x-xs,
    $btn-font-size-xs,
    $border-radius-sm
  );
}

// Extend Bootstrap mixins
@mixin custom-button-outline-variant($color) {
  @include button-outline-variant($color);
  
  &:hover {
    box-shadow: 0 4px 8px rgba($color, 0.3);
    transform: translateY(-2px);
  }
}

.btn-outline-custom {
  @include custom-button-outline-variant($custom);
}

// Custom form controls
$input-focus-border-color: $primary;
$input-focus-box-shadow: 0 0 0 0.25rem rgba($primary, 0.25);

// Card customizations
$card-border-radius: $border-radius-lg;
$card-box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);

.card-hover {
  @extend .card;
  transition: transform 0.2s, box-shadow 0.2s;
  
  &:hover {
    transform: translateY(-4px);
    box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
  }
}

19.2 Foundation Framework Integration

Feature Configuration File/Setting Purpose
Foundation Settings $foundation-palette _settings.scss Color system
Grid Configuration xy-grid or float grid Grid mixins Layout system
Motion UI Animation library motion-ui settings Transitions/animations
Component Sass Selective imports foundation.scss Tree shaking
Breakpoint Mgmt $breakpoints map Responsive helpers Media queries

Example: Foundation customization setup

// custom-foundation.scss

// 1. Import Foundation settings (copy from node_modules)
@import 'foundation-sites/scss/foundation';

// 2. Override Foundation variables
$foundation-palette: (
  primary: #1779ba,
  secondary: #767676,
  success: #3adb76,
  warning: #ffae00,
  alert: #cc4b37,
  custom: #5e35b1
);

// Grid settings
$grid-row-width: 1200px;
$grid-column-count: 12;
$grid-column-gutter: 30px;

// Breakpoints
$breakpoints: (
  small: 0,
  medium: 640px,
  large: 1024px,
  xlarge: 1200px,
  xxlarge: 1440px
);

// Typography
$header-font-family: 'Roboto', sans-serif;
$body-font-family: 'Open Sans', sans-serif;
$global-font-size: 16px;
$global-lineheight: 1.5;

// 3. Include Foundation components (selective)
@include foundation-global-styles;
@include foundation-xy-grid-classes;
@include foundation-typography;
@include foundation-button;
@include foundation-forms;
@include foundation-visibility-classes;
@include foundation-float-classes;
@include foundation-flex-classes;

// Skip unneeded components to reduce size
// @include foundation-accordion;
// @include foundation-badge;
// @include foundation-breadcrumbs;
// @include foundation-card;
// etc.

// 4. Custom extensions
.button.custom {
  background-color: map-get($foundation-palette, custom);
  
  &:hover {
    background-color: darken(map-get($foundation-palette, custom), 10%);
  }
}

Example: Foundation XY Grid customization

// foundation-xy-grid-custom.scss

@import 'foundation-sites/scss/foundation';

// XY Grid settings
$xy-grid: true;
$grid-container: 1200px;
$grid-columns: 12;
$grid-margin-gutters: (
  small: 20px,
  medium: 30px
);
$grid-padding-gutters: $grid-margin-gutters;

// Custom grid classes
@include foundation-xy-grid-classes(
  $base-grid: true,
  $margin-grid: true,
  $padding-grid: true,
  $block-grid: true,
  $collapse: true,
  $offset: true,
  $vertical-grid: true,
  $frame-grid: false
);

// Custom grid utilities
@mixin custom-grid-container {
  @include xy-grid-container;
  padding-left: 1rem;
  padding-right: 1rem;
  
  @include breakpoint(large) {
    padding-left: 2rem;
    padding-right: 2rem;
  }
}

.custom-container {
  @include custom-grid-container;
}

// Responsive grid mixins
@mixin responsive-grid($columns) {
  @include xy-grid;
  
  @each $size, $width in $breakpoints {
    @include breakpoint($size) {
      @include xy-grid-layout(
        map-get($columns, $size),
        '.cell'
      );
    }
  }
}

// Usage
.product-grid {
  @include responsive-grid((
    small: 1,
    medium: 2,
    large: 3,
    xlarge: 4
  ));
}

Example: Foundation Motion UI integration

// foundation-motion-ui.scss

@import 'foundation-sites/scss/foundation';
@import 'motion-ui/motion-ui';

// Motion UI settings
$motion-ui-speeds: (
  default: 500ms,
  slow: 750ms,
  fast: 250ms
);

$motion-ui-easings: (
  linear: linear,
  ease: ease,
  ease-in: ease-in,
  ease-out: ease-out,
  ease-in-out: ease-in-out,
  bounce: cubic-bezier(0.5, 1.8, 0.9, 0.8)
);

// Include Motion UI
@include motion-ui-transitions;
@include motion-ui-animations;

// Custom animations using Motion UI
.fade-slide-in {
  @include mui-animation(fade);
  @include mui-animation(slide);
}

.scale-and-fade {
  @include mui-series {
    @include mui-animation(fade(in, 0, 1));
    @include mui-animation(scale(in, 0.5, 1));
  }
}

// Custom slide variants
@include mui-slide(
  $state: in,
  $direction: down,
  $amount: 100%
);

.slide-in-down {
  @include mui-animation(slide(in, down));
}

// Hinge animation
.hinge-out {
  @include mui-hinge(
    $state: out,
    $from: top,
    $axis: edge,
    $perspective: 2000px,
    $turn-origin: from-back
  );
}

// Queue animations
.complex-entrance {
  @include mui-queue(
    fade(in),
    slide(in, up, 50px),
    spin(in, cw, 1turn)
  );
  
  @include mui-duration(1s);
  @include mui-timing(ease-out);
}

19.3 CSS-in-JS Library Compatibility

Library SCSS Integration Approach Trade-offs
Styled Components sass plugin/babel-plugin Hybrid approach Build complexity
Emotion @emotion/css with SCSS Preprocessor + runtime Two style systems
JSS jss-plugin-nested Similar syntax Learning curve
Linaria Zero-runtime CSS-in-JS Build-time extraction Limited dynamic styles
Vanilla Extract TypeScript CSS modules Type-safe styles No runtime theming

Example: SCSS utilities for CSS-in-JS migration

// scss-to-js-helpers.scss

// Export SCSS variables to JavaScript
:export {
  primary: $primary;
  secondary: $secondary;
  success: $success;
  danger: $danger;
  // ... other variables
}

// Alternative: Use CSS custom properties for runtime access
:root {
  --color-primary: #{$primary};
  --color-secondary: #{$secondary};
  --spacing-sm: #{$spacing-sm};
  --spacing-md: #{$spacing-md};
  --spacing-lg: #{$spacing-lg};
  --border-radius: #{$border-radius};
  
  @each $name, $value in $breakpoints {
    --breakpoint-#{$name}: #{$value};
  }
}

// Mixin to convert SCSS styles to CSS custom properties
@mixin export-as-css-vars($map, $prefix: '') {
  @each $key, $value in $map {
    @if type-of($value) == 'map' {
      @include export-as-css-vars($value, '#{$prefix}#{$key}-');
    } @else {
      --#{$prefix}#{$key}: #{$value};
    }
  }
}

// Theme object for CSS-in-JS
$theme-export: (
  colors: (
    primary: $primary,
    secondary: $secondary,
    text: $text-color,
    background: $bg-color
  ),
  spacing: (
    xs: 0.25rem,
    sm: 0.5rem,
    md: 1rem,
    lg: 1.5rem,
    xl: 2rem
  ),
  typography: (
    fontFamily: $font-family-base,
    fontSize: (
      sm: 0.875rem,
      base: 1rem,
      lg: 1.25rem,
      xl: 1.5rem
    )
  )
);

:root {
  @include export-as-css-vars($theme-export);
}

// JavaScript usage:
// const primary = getComputedStyle(document.documentElement)
//   .getPropertyValue('--colors-primary');

Example: Styled Components with SCSS mixins

// styles/mixins.scss - Shared SCSS mixins

@mixin flex-center {
  display: flex;
  align-items: center;
  justify-content: center;
}

@mixin button-base {
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.2s;
  
  &:hover {
    transform: translateY(-2px);
  }
}

@mixin responsive-font($min-size, $max-size, $min-width: 320px, $max-width: 1200px) {
  font-size: $min-size;
  
  @media (min-width: $min-width) {
    font-size: calc(
      #{$min-size} + 
      (#{strip-unit($max-size)} - #{strip-unit($min-size)}) * 
      (100vw - #{$min-width}) / 
      (#{strip-unit($max-width)} - #{strip-unit($min-width)})
    );
  }
  
  @media (min-width: $max-width) {
    font-size: $max-size;
  }
}

// Component using Styled Components + SCSS
// Button.jsx
import styled from 'styled-components';

export const Button = styled.button`
  ${props => props.theme.mixins.buttonBase}
  
  background-color: ${props => props.theme.colors.primary};
  color: white;
  
  &:hover {
    background-color: ${props => props.theme.colors.primaryDark};
  }
  
  ${props => props.variant === 'outline' && `
    background-color: transparent;
    border: 2px solid ${props.theme.colors.primary};
    color: ${props.theme.colors.primary};
  `}
`;

// Theme object combining SCSS values
// theme.js
import scssVariables from './styles/variables.scss';

export const theme = {
  colors: {
    primary: scssVariables.primary,
    secondary: scssVariables.secondary,
    // ... other colors
  },
  spacing: {
    xs: '0.25rem',
    sm: '0.5rem',
    md: '1rem',
    lg: '1.5rem',
  },
  mixins: {
    buttonBase: `
      padding: 0.5rem 1rem;
      border: none;
      border-radius: 4px;
      cursor: pointer;
      transition: all 0.2s;
    `
  }
};

Example: Migrating SCSS utilities to CSS-in-JS

// SCSS original
// utilities.scss
@mixin truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

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

// CSS-in-JS equivalent (Emotion/Styled Components)
// utilities.js
export const truncate = css`
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
`;

export const visuallyHidden = css`
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
`;

// Or as styled-components helper
import { css } from 'styled-components';

export const mixins = {
  truncate: () => css`
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  `,
  
  visuallyHidden: () => css`
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  `,
  
  responsive: (minWidth, styles) => css`
    @media (min-width: ${minWidth}) {
      ${styles}
    }
  `
};

// Usage in component
import styled from 'styled-components';
import { mixins } from './utilities';

const Title = styled.h1`
  ${mixins.truncate()}
  color: ${props => props.theme.colors.primary};
  
  ${mixins.responsive('768px', css`
    font-size: 2rem;
  `)}
`;

19.4 React/Vue/Angular Component Styling

Framework SCSS Integration Scoping Method Best Practice
React CSS Modules / Sass loader Automatic class hashing Component co-location
Vue <style lang="scss"> scoped attribute Single File Components
Angular styleUrls / Sass in CLI ViewEncapsulation Component styles array
Svelte <style lang="scss"> Auto-scoped styles Component-level SCSS
Next.js CSS Modules (.module.scss) Local scoping Global + module mix

Example: React with CSS Modules and SCSS

// Button.module.scss
@import '../../styles/variables';
@import '../../styles/mixins';

.button {
  @include button-base;
  background-color: $primary;
  color: white;
  
  &:hover {
    background-color: darken($primary, 10%);
  }
  
  // Modifier classes
  &.outline {
    background-color: transparent;
    border: 2px solid $primary;
    color: $primary;
    
    &:hover {
      background-color: $primary;
      color: white;
    }
  }
  
  &.large {
    padding: 1rem 2rem;
    font-size: 1.25rem;
  }
  
  &.small {
    padding: 0.25rem 0.5rem;
    font-size: 0.875rem;
  }
  
  &.disabled {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
  }
}

.icon {
  margin-right: 0.5rem;
  
  .button.iconOnly & {
    margin-right: 0;
  }
}

// Button.jsx
import React from 'react';
import styles from './Button.module.scss';
import classNames from 'classnames';

export const Button = ({ 
  children, 
  variant = 'primary',
  size = 'medium',
  disabled = false,
  icon,
  iconOnly = false,
  ...props 
}) => {
  return (
    <button
      className={classNames(
        styles.button,
        styles[variant],
        styles[size],
        { [styles.disabled]: disabled },
        { [styles.iconOnly]: iconOnly }
      )}
      disabled={disabled}
      {...props}
    >
      {icon && <span className={styles.icon}>{icon}</span>}
      {!iconOnly && children}
    </button>
  );
};

// Usage
<Button variant="outline" size="large">Click Me</Button>

Example: Vue Single File Component with SCSS

<!-- Card.vue -->
<template>
  <div :class="['card', `card--${variant}`, { 'card--hoverable': hoverable }]">
    <div v-if="$slots.header" class="card__header">
      <slot name="header"></slot>
    </div>
    
    <div class="card__body">
      <slot></slot>
    </div>
    
    <div v-if="$slots.footer" class="card__footer">
      <slot name="footer"></slot>
    </div>
  </div>
</template>

<script>
export default {
  name: 'Card',
  props: {
    variant: {
      type: String,
      default: 'default',
      validator: (value) => ['default', 'primary', 'success', 'danger'].includes(value)
    },
    hoverable: {
      type: Boolean,
      default: false
    }
  }
};
</script>

<style lang="scss" scoped>
@import '@/styles/variables';
@import '@/styles/mixins';

.card {
  background-color: $card-bg;
  border: 1px solid $border-color;
  border-radius: $border-radius;
  overflow: hidden;
  
  &__header {
    padding: $spacing-md;
    border-bottom: 1px solid $border-color;
    font-weight: 600;
    background-color: $gray-50;
  }
  
  &__body {
    padding: $spacing-md;
  }
  
  &__footer {
    padding: $spacing-md;
    border-top: 1px solid $border-color;
    background-color: $gray-50;
  }
  
  // Variants
  &--primary {
    border-color: $primary;
    
    .card__header {
      background-color: $primary;
      color: white;
      border-bottom-color: darken($primary, 10%);
    }
  }
  
  &--success {
    border-color: $success;
    
    .card__header {
      background-color: $success;
      color: white;
    }
  }
  
  &--danger {
    border-color: $danger;
    
    .card__header {
      background-color: $danger;
      color: white;
    }
  }
  
  // Hoverable state
  &--hoverable {
    @include card-hover-effect;
    cursor: pointer;
  }
}

// Deep selector for slot content styling
::v-deep {
  .card__body {
    p:last-child {
      margin-bottom: 0;
    }
  }
}
</style>

<!-- Usage -->
<Card variant="primary" hoverable>
  <template #header>Card Title</template>
  <p>Card content goes here</p>
  <template #footer>Card Footer</template>
</Card>

Example: Angular component styling with SCSS

// alert.component.scss
@import 'src/styles/variables';
@import 'src/styles/mixins';

:host {
  display: block;
  margin-bottom: $spacing-md;
}

.alert {
  @include alert-base;
  padding: $spacing-md;
  border-radius: $border-radius;
  border-left: 4px solid transparent;
  position: relative;
  
  &__icon {
    margin-right: $spacing-sm;
    vertical-align: middle;
  }
  
  &__close {
    @include button-reset;
    position: absolute;
    top: $spacing-sm;
    right: $spacing-sm;
    font-size: 1.25rem;
    opacity: 0.5;
    cursor: pointer;
    
    &:hover {
      opacity: 1;
    }
  }
  
  &__title {
    font-weight: 600;
    margin-bottom: $spacing-xs;
  }
  
  &__message {
    margin: 0;
  }
  
  // Variants using maps
  @each $variant, $color in $alert-colors {
    &--#{$variant} {
      background-color: lighten($color, 45%);
      border-left-color: $color;
      color: darken($color, 20%);
      
      .alert__icon {
        color: $color;
      }
    }
  }
}

// alert.component.ts
import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-alert',
  templateUrl: './alert.component.html',
  styleUrls: ['./alert.component.scss'],
  // ViewEncapsulation options:
  // - Emulated (default): Scoped styles with attribute selectors
  // - None: Global styles
  // - ShadowDom: True Shadow DOM encapsulation
})
export class AlertComponent {
  @Input() variant: 'info' | 'success' | 'warning' | 'danger' = 'info';
  @Input() title?: string;
  @Input() dismissible = false;
  @Output() dismiss = new EventEmitter<void>();
  
  onClose(): void {
    this.dismiss.emit();
  }
}

// alert.component.html
<div class="alert alert--{{ variant }}">
  <span class="alert__icon">
    <!-- Icon SVG or component -->
  </span>
  
  <div class="alert__content">
    <div *ngIf="title" class="alert__title">{{ title }}</div>
    <p class="alert__message"><ng-content></ng-content></p>
  </div>
  
  <button
    *ngIf="dismissible"
    class="alert__close"
    (click)="onClose()"
    aria-label="Close"
  >
    &times;
  </button>
</div>

// Usage
<app-alert variant="success" title="Success!" [dismissible]="true">
  Your changes have been saved.
</app-alert>

19.5 Styled Components vs SCSS Comparison

Feature SCSS Styled Components Winner
Performance Build-time compilation Runtime style injection SCSS
Bundle Size Static CSS file ~15kb library overhead SCSS
Dynamic Theming CSS custom properties Theme provider + props Styled Components
Type Safety None (unless typed tokens) TypeScript integration Styled Components
Learning Curve CSS knowledge CSS + JS patterns SCSS
Component Scoping BEM or CSS Modules Automatic scoping Styled Components
SSR Support Native Requires setup SCSS
Conditional Styles Classes or mixins Props interpolation Styled Components

Example: Same component in SCSS vs Styled Components

// ===== SCSS Approach =====

// Button.module.scss
@import 'variables';

.button {
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 4px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.2s;
  
  &:hover {
    transform: translateY(-2px);
  }
}

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

.secondary {
  background-color: $secondary;
  color: white;
}

.large {
  padding: 1rem 2rem;
  font-size: 1.25rem;
}

.small {
  padding: 0.25rem 0.5rem;
  font-size: 0.875rem;
}

// Button.jsx
import styles from './Button.module.scss';
import classNames from 'classnames';

const Button = ({ variant = 'primary', size = 'medium', children }) => (
  <button className={classNames(
    styles.button,
    styles[variant],
    styles[size]
  )}>
    {children}
  </button>
);

// ===== Styled Components Approach =====

import styled from 'styled-components';

const Button = styled.button`
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 4px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.2s;
  
  /* Dynamic styles based on props */
  background-color: ${props => 
    props.variant === 'primary' ? props.theme.colors.primary :
    props.variant === 'secondary' ? props.theme.colors.secondary :
    props.theme.colors.default
  };
  
  color: white;
  
  /* Size variants */
  ${props => props.size === 'large' && `
    padding: 1rem 2rem;
    font-size: 1.25rem;
  `}
  
  ${props => props.size === 'small' && `
    padding: 0.25rem 0.5rem;
    font-size: 0.875rem;
  `}
  
  &:hover {
    transform: translateY(-2px);
  }
`;

// Usage is the same
<Button variant="primary" size="large">Click Me</Button>

// ===== Hybrid Approach: Best of Both Worlds =====

// Use SCSS for static styles, Styled Components for dynamic
import styled from 'styled-components';
import './Button.scss'; // Import base SCSS styles

const DynamicButton = styled.button.attrs(props => ({
  className: `button button--${props.variant} button--${props.size}`
}))`
  /* Only dynamic, component-specific overrides */
  ${props => props.highlighted && `
    box-shadow: 0 0 0 3px ${props.theme.colors.highlight};
  `}
  
  ${props => props.loading && `
    opacity: 0.6;
    cursor: wait;
  `}
`;

Example: Performance considerations

// SCSS - Build-time optimization
// All styles compiled to static CSS
// Output: button.abc123.css (minified, cached)

.button { /* ... */ }
.button--primary { /* ... */ }
.button--large { /* ... */ }

// Pros:
// ✅ No runtime overhead
// ✅ Better initial load performance
// ✅ Works without JavaScript
// ✅ Easier to debug in DevTools
// ✅ Better caching (static file)

// Cons:
// ❌ Less dynamic (need CSS vars for theming)
// ❌ Manual scoping (BEM, modules)
// ❌ Harder to use component props
// ❌ No type safety

// ===================================

// Styled Components - Runtime styles
import styled from 'styled-components';

const Button = styled.button`
  background: ${p => p.theme.colors[p.variant]};
`;

// Generated at runtime:
// <style data-styled="active">
//   .sc-bdnylx { /* ... */ }
// </style>

// Pros:
// ✅ Fully dynamic (props, theme)
// ✅ Automatic scoping
// ✅ TypeScript support
// ✅ Co-located with component
// ✅ Dead code elimination

// Cons:
// ❌ Runtime performance cost
// ❌ Larger bundle size (~15kb)
// ❌ SSR complexity
// ❌ Styles in JS bundle (not cached separately)
// ❌ Flash of unstyled content (FOUC)

// ===================================

// Best Practice: Hybrid Approach
// Use SCSS for:
// - Global styles and resets
// - Design system tokens
// - Static utility classes
// - Third-party component overrides

// Use Styled Components for:
// - Highly dynamic components
// - Component-specific styles
// - Theme-dependent UI
// - Type-safe style APIs

// Example hybrid setup:
// _global.scss - Global styles
@import 'reset';
@import 'variables';
@import 'utilities';

// Component with hybrid approach
import styled from 'styled-components';
import './Button.scss'; // Base styles

const Button = styled.button`
  /* Inherit base .button class from SCSS */
  ${props => props.dynamic && `
    /* Only add dynamic overrides */
    background: ${props.theme.colors[props.variant]};
  `}
`;

19.6 Design Token Integration (Style Dictionary)

Feature Implementation Output Use Case
Token Definition JSON/YAML design tokens Platform-agnostic source Single source of truth
SCSS Transform Style Dictionary build SCSS variables Web styling
CSS Custom Props Custom format template :root with --vars Runtime theming
Multi-platform iOS, Android, Web outputs Native + web tokens Cross-platform apps
Figma Sync figma-tokens plugin Automated updates Design-dev sync

Example: Style Dictionary configuration

// config.json - Style Dictionary configuration
{
  "source": ["tokens/**/*.json"],
  "platforms": {
    "scss": {
      "transformGroup": "scss",
      "buildPath": "src/styles/",
      "files": [
        {
          "destination": "_tokens.scss",
          "format": "scss/variables"
        },
        {
          "destination": "_tokens-map.scss",
          "format": "scss/map-deep"
        }
      ]
    },
    "css": {
      "transformGroup": "css",
      "buildPath": "src/styles/",
      "files": [
        {
          "destination": "tokens.css",
          "format": "css/variables"
        }
      ]
    }
  }
}

// tokens/color.json - Design tokens
{
  "color": {
    "brand": {
      "primary": { "value": "#0066cc" },
      "secondary": { "value": "#6c757d" }
    },
    "semantic": {
      "success": { "value": "#28a745" },
      "danger": { "value": "#dc3545" },
      "warning": { "value": "#ffc107" },
      "info": { "value": "#17a2b8" }
    },
    "neutral": {
      "100": { "value": "#f8f9fa" },
      "200": { "value": "#e9ecef" },
      "300": { "value": "#dee2e6" },
      "800": { "value": "#343a40" },
      "900": { "value": "#212529" }
    }
  }
}

// tokens/spacing.json
{
  "spacing": {
    "xs": { "value": "0.25rem" },
    "sm": { "value": "0.5rem" },
    "md": { "value": "1rem" },
    "lg": { "value": "1.5rem" },
    "xl": { "value": "2rem" },
    "2xl": { "value": "3rem" }
  }
}

// Generated output: _tokens.scss
$color-brand-primary: #0066cc;
$color-brand-secondary: #6c757d;
$color-semantic-success: #28a745;
$color-semantic-danger: #dc3545;
$spacing-xs: 0.25rem;
$spacing-sm: 0.5rem;
// ... etc

// Generated output: tokens.css
:root {
  --color-brand-primary: #0066cc;
  --color-brand-secondary: #6c757d;
  --color-semantic-success: #28a745;
  --spacing-xs: 0.25rem;
  --spacing-sm: 0.5rem;
}

Example: Advanced token transformations

// build.js - Custom Style Dictionary build
const StyleDictionary = require('style-dictionary');

// Custom transform for color opacity
StyleDictionary.registerTransform({
  name: 'color/alpha',
  type: 'value',
  matcher: token => token.attributes.category === 'color',
  transformer: token => {
    const { value, alpha } = token;
    if (alpha) {
      // Convert hex to rgba with alpha
      const r = parseInt(value.slice(1, 3), 16);
      const g = parseInt(value.slice(3, 5), 16);
      const b = parseInt(value.slice(5, 7), 16);
      return `rgba(${r}, ${g}, ${b}, ${alpha})`;
    }
    return value;
  }
});

// Custom format for SCSS map
StyleDictionary.registerFormat({
  name: 'scss/map-nested',
  formatter: ({ dictionary }) => {
    const tokensMap = dictionary.allTokens.reduce((acc, token) => {
      const path = token.path;
      let current = acc;
      
      path.forEach((key, index) => {
        if (index === path.length - 1) {
          current[key] = token.value;
        } else {
          current[key] = current[key] || {};
          current = current[key];
        }
      });
      
      return acc;
    }, {});
    
    const mapToScss = (obj, indent = 1) => {
      const spaces = '  '.repeat(indent);
      const entries = Object.entries(obj).map(([key, value]) => {
        if (typeof value === 'object') {
          return `${spaces}'${key}': (\n${mapToScss(value, indent + 1)}\n${spaces})`;
        }
        return `${spaces}'${key}': ${value}`;
      });
      return entries.join(',\n');
    };
    
    return `$tokens: (\n${mapToScss(tokensMap)}\n);`;
  }
});

// Build
const sd = StyleDictionary.extend({
  source: ['tokens/**/*.json'],
  platforms: {
    scss: {
      transforms: ['attribute/cti', 'name/cti/kebab', 'color/alpha'],
      buildPath: 'src/styles/',
      files: [
        {
          destination: '_tokens.scss',
          format: 'scss/variables'
        },
        {
          destination: '_tokens-map.scss',
          format: 'scss/map-nested'
        }
      ]
    }
  }
});

sd.buildAllPlatforms();

// Generated _tokens-map.scss
$tokens: (
  'color': (
    'brand': (
      'primary': #0066cc,
      'secondary': #6c757d
    ),
    'semantic': (
      'success': #28a745,
      'danger': #dc3545
    )
  ),
  'spacing': (
    'xs': 0.25rem,
    'sm': 0.5rem,
    'md': 1rem
  )
);

// Usage in SCSS
@use 'sass:map';

.button {
  background-color: map.get($tokens, 'color', 'brand', 'primary');
  padding: map.get($tokens, 'spacing', 'md');
}

Example: Semantic tokens and theming

// tokens/base.json - Base design tokens
{
  "color": {
    "blue": {
      "100": { "value": "#e3f2fd" },
      "500": { "value": "#2196f3" },
      "900": { "value": "#0d47a1" }
    },
    "gray": {
      "100": { "value": "#f5f5f5" },
      "500": { "value": "#9e9e9e" },
      "900": { "value": "#212121" }
    }
  }
}

// tokens/semantic.json - Semantic tokens referencing base
{
  "color": {
    "text": {
      "primary": { "value": "{color.gray.900}" },
      "secondary": { "value": "{color.gray.500}" },
      "inverse": { "value": "#ffffff" }
    },
    "background": {
      "default": { "value": "#ffffff" },
      "subtle": { "value": "{color.gray.100}" }
    },
    "action": {
      "primary": { "value": "{color.blue.500}" },
      "primaryHover": { "value": "{color.blue.900}" }
    }
  }
}

// tokens/dark-theme.json - Dark mode overrides
{
  "color": {
    "text": {
      "primary": { "value": "#ffffff" },
      "secondary": { "value": "{color.gray.100}" }
    },
    "background": {
      "default": { "value": "{color.gray.900}" },
      "subtle": { "value": "#1a1a1a" }
    }
  }
}

// build-themes.js
const StyleDictionary = require('style-dictionary');

// Build light theme
const lightTheme = StyleDictionary.extend({
  include: ['tokens/base.json'],
  source: ['tokens/semantic.json'],
  platforms: {
    scss: {
      transformGroup: 'scss',
      buildPath: 'src/styles/themes/',
      files: [{
        destination: '_light.scss',
        format: 'scss/variables',
        options: { outputReferences: true }
      }]
    }
  }
});

// Build dark theme
const darkTheme = StyleDictionary.extend({
  include: ['tokens/base.json', 'tokens/semantic.json'],
  source: ['tokens/dark-theme.json'],
  platforms: {
    scss: {
      transformGroup: 'scss',
      buildPath: 'src/styles/themes/',
      files: [{
        destination: '_dark.scss',
        format: 'scss/variables'
      }]
    }
  }
});

lightTheme.buildAllPlatforms();
darkTheme.buildAllPlatforms();

// Usage in SCSS
// main.scss
:root {
  @import 'themes/light';
}

[data-theme="dark"] {
  @import 'themes/dark';
}

// Or with CSS custom properties
:root {
  --color-text-primary: #{$color-text-primary};
  --color-background-default: #{$color-background-default};
}

[data-theme="dark"] {
  --color-text-primary: #{$color-text-primary-dark};
  --color-background-default: #{$color-background-default-dark};
}

Framework Integration Summary

  • Bootstrap/Foundation: Override variables before importing, use selective imports for smaller bundles
  • CSS-in-JS compatibility: Export SCSS as CSS custom properties or use :export for JS consumption
  • Component frameworks: Use CSS Modules (React), scoped styles (Vue), or ViewEncapsulation (Angular)
  • SCSS vs Styled Components: SCSS for static/performance, Styled Components for dynamic/type-safe styles
  • Design tokens: Use Style Dictionary for platform-agnostic tokens, generate SCSS and CSS variables
  • Hybrid approach: Combine SCSS for global/static styles with CSS-in-JS for component dynamics
  • Token theming: Build multiple theme outputs from semantic tokens for light/dark modes
  • Type safety: Generate TypeScript definitions from design tokens for end-to-end type safety
Note: Modern frameworks support SCSS natively, but choose the right tool for each use case. Use SCSS for global design systems and CSS-in-JS for component-level dynamic styling. Design tokens provide the bridge between design tools and code.

20. Development Workflow and Tooling

20.1 Sass Linting with stylelint Configuration

Configuration Plugin/Rule Purpose Example Rule
stylelint-scss SCSS-specific rules Enforce SCSS syntax at-rule-no-unknown
Standard Config stylelint-config-standard-scss Recommended rules Comprehensive base
Order Plugin stylelint-order Property ordering Consistent structure
BEM Plugin stylelint-selector-bem-pattern BEM validation Naming conventions
Custom Rules Project-specific config Team standards Brand compliance

Example: Complete stylelint configuration for SCSS

// .stylelintrc.json
{
  "extends": [
    "stylelint-config-standard-scss",
    "stylelint-config-prettier-scss"
  ],
  "plugins": [
    "stylelint-scss",
    "stylelint-order"
  ],
  "rules": {
    // SCSS-specific rules
    "scss/at-rule-no-unknown": true,
    "scss/at-import-partial-extension": "never",
    "scss/dollar-variable-pattern": "^[a-z][a-z0-9]*(-[a-z0-9]+)*$",
    "scss/percent-placeholder-pattern": "^[a-z][a-z0-9]*(-[a-z0-9]+)*$",
    "scss/at-mixin-pattern": "^[a-z][a-z0-9]*(-[a-z0-9]+)*$",
    "scss/at-function-pattern": "^[a-z][a-z0-9]*(-[a-z0-9]+)*$",
    "scss/selector-no-redundant-nesting-selector": true,
    "scss/no-duplicate-dollar-variables": true,
    "scss/no-duplicate-mixins": true,
    "scss/operator-no-newline-after": true,
    "scss/operator-no-unspaced": true,
    "scss/dimension-no-non-numeric-values": true,
    
    // Property ordering
    "order/properties-order": [
      "position",
      "top",
      "right",
      "bottom",
      "left",
      "z-index",
      "display",
      "flex",
      "flex-direction",
      "justify-content",
      "align-items",
      "width",
      "height",
      "margin",
      "padding",
      "border",
      "background",
      "color",
      "font",
      "text-align",
      "transition",
      "transform"
    ],
    
    // General rules
    "color-hex-length": "short",
    "color-named": "never",
    "declaration-no-important": true,
    "max-nesting-depth": 3,
    "selector-max-id": 0,
    "selector-max-compound-selectors": 4,
    "selector-max-specificity": "0,4,0",
    "selector-class-pattern": "^[a-z][a-z0-9]*(-[a-z0-9]+)*(__[a-z0-9]+(-[a-z0-9]+)*)?(--[a-z0-9]+(-[a-z0-9]+)*)?$",
    
    // Comments
    "comment-empty-line-before": [
      "always",
      {
        "except": ["first-nested"],
        "ignore": ["stylelint-commands"]
      }
    ],
    
    // Disabled rules
    "no-descending-specificity": null,
    "selector-pseudo-class-no-unknown": [
      true,
      {
        "ignorePseudoClasses": ["global", "local"]
      }
    ]
  },
  "ignoreFiles": [
    "node_modules/**",
    "dist/**",
    "build/**",
    "*.min.css"
  ]
}

// package.json scripts
{
  "scripts": {
    "lint:scss": "stylelint '**/*.scss'",
    "lint:scss:fix": "stylelint '**/*.scss' --fix",
    "lint:scss:report": "stylelint '**/*.scss' --formatter json --output-file stylelint-report.json"
  }
}

Example: Custom stylelint rules for team standards

// .stylelintrc.js - Advanced configuration
module.exports = {
  extends: ['stylelint-config-standard-scss'],
  plugins: [
    'stylelint-scss',
    'stylelint-order',
    'stylelint-selector-bem-pattern'
  ],
  rules: {
    // BEM pattern enforcement
    'plugin/selector-bem-pattern': {
      preset: 'bem',
      componentName: '[A-Z]+',
      componentSelectors: {
        initial: "^\\.{componentName}(?:-[a-z]+)*$",
        combined: "^\\.combined-{componentName}-[a-z]+$"
      },
      utilitySelectors: "^\\.util-[a-z]+$"
    },
    
    // Custom SCSS variable naming
    "scss/dollar-variable-pattern": [
      "^(_)?[a-z][a-z0-9]*(-[a-z0-9]+)*$",
      {
        message: "Expected variable to be kebab-case (use _ prefix for private)",
        ignore: ["global"]
      }
    ],
    
    // Enforce @use over @import
    'scss/at-import-no-partial-leading-underscore': true,
    'scss/load-no-partial-leading-underscore': true,
    'at-rule-disallowed-list': ['import'],
    
    // Mixin and function standards
    'scss/at-mixin-argumentless-call-parentheses': 'always',
    'scss/at-else-closing-brace-newline-after': 'always-last-in-chain',
    'scss/at-else-closing-brace-space-after': 'always-intermediate',
    'scss/at-else-empty-line-before': 'never',
    'scss/at-if-closing-brace-newline-after': 'always-last-in-chain',
    'scss/at-if-closing-brace-space-after': 'always-intermediate',
    
    // Color management
    'color-function-notation': 'modern',
    'color-hex-case': 'lower',
    'scss/dollar-variable-colon-space-after': 'always',
    'scss/dollar-variable-colon-space-before': 'never',
    
    // Property ordering with groups
    'order/properties-order': [
      {
        groupName: 'positioning',
        properties: ['position', 'top', 'right', 'bottom', 'left', 'z-index']
      },
      {
        groupName: 'box-model',
        properties: ['display', 'flex', 'grid', 'width', 'height', 'margin', 'padding']
      },
      {
        groupName: 'typography',
        properties: ['font-family', 'font-size', 'line-height', 'color', 'text-align']
      },
      {
        groupName: 'visual',
        properties: ['background', 'border', 'border-radius', 'box-shadow', 'opacity']
      },
      {
        groupName: 'animation',
        properties: ['transition', 'animation', 'transform']
      }
    ],
    
    // Limit complexity
    'max-nesting-depth': [
      3,
      {
        ignore: ['blockless-at-rules', 'pseudo-classes']
      }
    ],
    
    // Project-specific rules
    'declaration-property-value-disallowed-list': {
      '/^border/': ['none'],
      'transition': ['/all/']
    },
    
    // Disable for SCSS features
    'at-rule-no-unknown': null,
    'function-no-unknown': null
  }
};

// VS Code settings.json integration
{
  "stylelint.enable": true,
  "stylelint.validate": ["css", "scss"],
  "editor.codeActionsOnSave": {
    "source.fixAll.stylelint": true
  }
}

Example: Stylelint ignore patterns and overrides

// .stylelintrc.json with overrides
{
  "extends": "stylelint-config-standard-scss",
  "rules": {
    "max-nesting-depth": 3,
    "selector-max-id": 0
  },
  "overrides": [
    {
      // Stricter rules for components
      "files": ["src/components/**/*.scss"],
      "rules": {
        "max-nesting-depth": 2,
        "selector-class-pattern": "^[a-z][a-z0-9]*(__[a-z0-9]+)?(--[a-z0-9]+)?$"
      }
    },
    {
      // Relaxed rules for utilities
      "files": ["src/utilities/**/*.scss"],
      "rules": {
        "declaration-no-important": null,
        "max-nesting-depth": 1
      }
    },
    {
      // Legacy code (gradual migration)
      "files": ["src/legacy/**/*.scss"],
      "rules": {
        "max-nesting-depth": null,
        "selector-max-id": null,
        "at-rule-disallowed-list": null
      }
    }
  ],
  "ignoreFiles": [
    "**/*.min.css",
    "**/vendor/**",
    "**/node_modules/**"
  ]
}

// .stylelintignore
node_modules/
dist/
build/
*.min.css
vendor/
coverage/

# Inline ignore comments in SCSS
.legacy-component {
  /* stylelint-disable-next-line selector-max-id */
  #legacy-id {
    color: red;
  }
}

.exception {
  /* stylelint-disable declaration-no-important */
  color: blue !important;
  /* stylelint-enable declaration-no-important */
}

20.2 Prettier Formatting and Code Style

Setting Option Recommendation Reason
printWidth 80-120 characters 100 Readability
singleQuote true/false true Consistency
tabWidth 2/4 spaces 2 Standard SCSS
trailingComma none/es5/all es5 Git diffs
bracketSpacing true/false true Readability

Example: Prettier configuration for SCSS

// .prettierrc.json
{
  "printWidth": 100,
  "tabWidth": 2,
  "useTabs": false,
  "semi": true,
  "singleQuote": true,
  "quoteProps": "as-needed",
  "trailingComma": "es5",
  "bracketSpacing": true,
  "arrowParens": "always",
  "endOfLine": "lf",
  "overrides": [
    {
      "files": "*.scss",
      "options": {
        "singleQuote": false,
        "parser": "scss"
      }
    },
    {
      "files": "*.json",
      "options": {
        "printWidth": 80,
        "tabWidth": 2
      }
    }
  ]
}

// .prettierignore
node_modules/
dist/
build/
coverage/
*.min.css
*.min.js
package-lock.json
yarn.lock
pnpm-lock.yaml

// package.json scripts
{
  "scripts": {
    "format": "prettier --write '**/*.{scss,css,js,jsx,ts,tsx,json,md}'",
    "format:check": "prettier --check '**/*.{scss,css,js,jsx,ts,tsx,json,md}'",
    "format:scss": "prettier --write '**/*.scss'"
  },
  "devDependencies": {
    "prettier": "^3.1.0"
  }
}

Example: EditorConfig for consistent formatting

// .editorconfig - Works with Prettier and most editors
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[*.{js,jsx,ts,tsx,json}]
indent_style = space
indent_size = 2

[*.{scss,css}]
indent_style = space
indent_size = 2
quote_type = double

[*.md]
max_line_length = off
trim_trailing_whitespace = false

[{package.json,.prettierrc,.stylelintrc}]
indent_style = space
indent_size = 2

[*.yml]
indent_style = space
indent_size = 2

// Example SCSS before Prettier
.button{background-color:#0066cc;color:white;padding:10px 20px;&:hover{background-color:darken(#0066cc,10%);}}

// After Prettier
.button {
  background-color: #0066cc;
  color: white;
  padding: 10px 20px;

  &:hover {
    background-color: darken(#0066cc, 10%);
  }
}

Example: Integration with stylelint and Prettier

// Combine stylelint + Prettier for best results

// 1. Install dependencies
npm install -D prettier stylelint stylelint-config-prettier-scss

// 2. .stylelintrc.json
{
  "extends": [
    "stylelint-config-standard-scss",
    "stylelint-config-prettier-scss"  // Disables conflicting rules
  ],
  "rules": {
    // Your custom rules
  }
}

// 3. package.json scripts
{
  "scripts": {
    "lint": "npm run lint:scss && npm run format:check",
    "lint:scss": "stylelint '**/*.scss'",
    "lint:fix": "npm run lint:scss:fix && npm run format",
    "lint:scss:fix": "stylelint '**/*.scss' --fix",
    "format": "prettier --write '**/*.{scss,css,js,json}'",
    "format:check": "prettier --check '**/*.{scss,css,js,json}'"
  }
}

// 4. VS Code settings.json
{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.stylelint": true
  },
  "[scss]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.formatOnSave": true
  },
  "stylelint.enable": true,
  "stylelint.validate": ["css", "scss"],
  "prettier.requireConfig": true
}

// 5. Workflow
// 1. Stylelint fixes structural/logical issues
// 2. Prettier formats the code aesthetically
// 3. Both run automatically on save in VS Code
// 4. Pre-commit hooks enforce on all commits

20.3 VS Code Extensions and IntelliSense

Extension ID Features Priority
SCSS IntelliSense mrmlnc.vscode-scss Autocomplete, go-to-def Essential
Stylelint stylelint.vscode-stylelint Linting errors/warnings Essential
Prettier esbenp.prettier-vscode Code formatting Essential
Color Highlight naumovs.color-highlight Visual color preview Recommended
CSS Peek pranaygp.vscode-css-peek Class definition lookup Recommended

Example: VS Code workspace settings for SCSS

// .vscode/settings.json
{
  // Editor
  "editor.tabSize": 2,
  "editor.insertSpaces": true,
  "editor.formatOnSave": true,
  "editor.formatOnPaste": false,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.codeActionsOnSave": {
    "source.fixAll.stylelint": true,
    "source.organizeImports": false
  },
  
  // SCSS specific
  "[scss]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.suggest.insertMode": "replace",
    "editor.quickSuggestions": {
      "other": true,
      "comments": false,
      "strings": true
    }
  },
  
  // Stylelint
  "stylelint.enable": true,
  "stylelint.validate": ["css", "scss", "sass"],
  "stylelint.snippet": ["css", "scss"],
  "css.validate": false,  // Disable default CSS validation
  "scss.validate": false, // Let stylelint handle it
  
  // Prettier
  "prettier.requireConfig": true,
  "prettier.useEditorConfig": true,
  
  // SCSS IntelliSense
  "scss.scannerDepth": 30,
  "scss.scannerExclude": [
    "**/.git",
    "**/node_modules",
    "**/bower_components"
  ],
  "scss.implicitlyLabel": "(implicitly)",
  
  // Color decorators
  "editor.colorDecorators": true,
  
  // Emmet
  "emmet.includeLanguages": {
    "scss": "css"
  },
  "emmet.syntaxProfiles": {
    "scss": "css"
  },
  
  // Files
  "files.associations": {
    "*.scss": "scss"
  },
  "files.exclude": {
    "**/.git": true,
    "**/node_modules": true,
    "**/.DS_Store": true,
    "**/dist": true,
    "**/build": true
  },
  
  // Search
  "search.exclude": {
    "**/node_modules": true,
    "**/dist": true,
    "**/*.min.css": true
  }
}
// .vscode/extensions.json
{
  "recommendations": [
    // Essential for SCSS development
    "stylelint.vscode-stylelint",
    "esbenp.prettier-vscode",
    "mrmlnc.vscode-scss",
    
    // Enhanced developer experience
    "naumovs.color-highlight",
    "pranaygp.vscode-css-peek",
    "csstools.postcss",
    
    // General productivity
    "editorconfig.editorconfig",
    "usernamehw.errorlens",
    "christian-kohler.path-intellisense",
    
    // Git integration
    "eamodio.gitlens",
    "mhutchie.git-graph"
  ],
  "unwantedRecommendations": [
    "hookyqr.beautify",  // Use Prettier instead
    "HookyQR.beautify"
  ]
}

// .vscode/tasks.json - Build tasks
{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Watch SCSS",
      "type": "shell",
      "command": "npm run watch:scss",
      "group": {
        "kind": "build",
        "isDefault": true
      },
      "isBackground": true,
      "problemMatcher": {
        "owner": "scss",
        "fileLocation": ["relative", "${workspaceFolder}"],
        "pattern": {
          "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
          "file": 1,
          "line": 2,
          "column": 3,
          "severity": 4,
          "message": 5
        },
        "background": {
          "activeOnStart": true,
          "beginsPattern": "^Compiling",
          "endsPattern": "^Compiled"
        }
      }
    },
    {
      "label": "Lint SCSS",
      "type": "shell",
      "command": "npm run lint:scss",
      "group": "test",
      "presentation": {
        "reveal": "always",
        "panel": "new"
      }
    },
    {
      "label": "Format SCSS",
      "type": "shell",
      "command": "npm run format:scss",
      "group": "none"
    }
  ]
}

Example: Custom VS Code snippets for SCSS

// .vscode/scss.code-snippets
{
  "SCSS Mixin": {
    "prefix": "mixin",
    "body": [
      "@mixin ${1:name}($2) {",
      "  $3",
      "}"
    ],
    "description": "Create a SCSS mixin"
  },
  
  "SCSS Function": {
    "prefix": "function",
    "body": [
      "@function ${1:name}($2) {",
      "  @return $3;",
      "}"
    ],
    "description": "Create a SCSS function"
  },
  
  "SCSS Use Module": {
    "prefix": "use",
    "body": "@use '${1:module}' as ${2:alias};",
    "description": "Import SCSS module with @use"
  },
  
  "SCSS Forward Module": {
    "prefix": "forward",
    "body": "@forward '${1:module}';",
    "description": "Forward SCSS module"
  },
  
  "SCSS Media Query": {
    "prefix": "media",
    "body": [
      "@media (min-width: ${1:768px}) {",
      "  $2",
      "}"
    ],
    "description": "Create a media query"
  },
  
  "SCSS For Loop": {
    "prefix": "for",
    "body": [
      "@for \\${1:i} from ${2:1} through ${3:10} {",
      "  $4",
      "}"
    ],
    "description": "Create a @for loop"
  },
  
  "SCSS Each Loop": {
    "prefix": "each",
    "body": [
      "@each \\${1:item} in ${2:list} {",
      "  $3",
      "}"
    ],
    "description": "Create an @each loop"
  },
  
  "BEM Block": {
    "prefix": "bem-block",
    "body": [
      ".${1:block} {",
      "  $2",
      "  ",
      "  &__${3:element} {",
      "    $4",
      "  }",
      "  ",
      "  &--${5:modifier} {",
      "    $6",
      "  }",
      "}"
    ],
    "description": "Create a BEM block structure"
  },
  
  "Responsive Mixin": {
    "prefix": "responsive",
    "body": [
      "@mixin responsive(\\$breakpoint) {",
      "  @if \\$breakpoint == mobile {",
      "    @media (max-width: 767px) { @content; }",
      "  } @else if \\$breakpoint == tablet {",
      "    @media (min-width: 768px) and (max-width: 1023px) { @content; }",
      "  } @else if \\$breakpoint == desktop {",
      "    @media (min-width: 1024px) { @content; }",
      "  }",
      "}"
    ],
    "description": "Create a responsive mixin"
  }
}

20.4 Git Hooks and Pre-commit Validation

Tool Hook Type Action Purpose
Husky pre-commit Run linters Quality gate
lint-staged pre-commit Lint staged files only Fast validation
commitlint commit-msg Validate commit messages Clean history
pre-push pre-push Run full test suite Prevent broken pushes
prepare-commit-msg commit template Auto-add ticket number Traceability

Example: Husky and lint-staged setup

// 1. Install dependencies
npm install -D husky lint-staged

// 2. Initialize husky
npx husky install
npm pkg set scripts.prepare="husky install"

// 3. package.json configuration
{
  "scripts": {
    "prepare": "husky install",
    "lint:scss": "stylelint '**/*.scss'",
    "format": "prettier --write"
  },
  "lint-staged": {
    "*.scss": [
      "stylelint --fix",
      "prettier --write"
    ],
    "*.{js,jsx,ts,tsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{json,md,yml}": [
      "prettier --write"
    ]
  },
  "devDependencies": {
    "husky": "^8.0.0",
    "lint-staged": "^15.0.0",
    "stylelint": "^16.0.0",
    "prettier": "^3.0.0"
  }
}

// 4. Create pre-commit hook
npx husky add .husky/pre-commit "npx lint-staged"

// .husky/pre-commit
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

echo "🔍 Running pre-commit checks..."
npx lint-staged

// 5. Create commit-msg hook (optional)
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'

// .commitlintrc.json
{
  "extends": ["@commitlint/config-conventional"],
  "rules": {
    "type-enum": [
      2,
      "always",
      [
        "feat",
        "fix",
        "docs",
        "style",
        "refactor",
        "perf",
        "test",
        "chore"
      ]
    ],
    "subject-case": [2, "always", "sentence-case"]
  }
}

// Example commit message:
// feat: add new button component styles
// fix: resolve Safari flexbox layout issue
// style: format SCSS files with Prettier

Example: Advanced pre-commit workflow

// .husky/pre-commit - Comprehensive checks
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

echo "🚀 Running pre-commit hooks..."

# 1. Run lint-staged for quick fixes
echo "📝 Linting and formatting staged files..."
npx lint-staged

# 2. Check for TODO/FIXME comments (optional warning)
echo "🔍 Checking for TODO/FIXME..."
git diff --cached --name-only --diff-filter=ACM | \
  xargs grep -n -E "TODO|FIXME" && \
  echo "⚠️  Warning: TODO/FIXME found in staged files" || true

# 3. Run type checking (if TypeScript)
if [ -f "tsconfig.json" ]; then
  echo "🔷 Type checking..."
  npm run type-check
fi

# 4. Check bundle size (optional)
# npm run size-check

echo "✅ Pre-commit checks passed!"

// package.json - Extended lint-staged config
{
  "lint-staged": {
    "*.scss": [
      "stylelint --fix",
      "prettier --write",
      "git add"
    ],
    "*.{css,scss}": [
      // Custom script to check for vendor prefixes
      "node scripts/check-prefixes.js"
    ],
    "package.json": [
      // Sort package.json
      "sort-package-json",
      "prettier --write"
    ]
  }
}

// scripts/check-prefixes.js
const fs = require('fs');
const path = require('path');

// Check if files contain manual vendor prefixes
// (should use autoprefixer instead)
process.argv.slice(2).forEach(file => {
  const content = fs.readFileSync(file, 'utf8');
  const vendorPrefixes = /-webkit-|-moz-|-ms-|-o-/g;
  
  if (vendorPrefixes.test(content)) {
    console.error(` Found vendor prefixes in ${file}`);
    console.error('   Use autoprefixer instead of manual prefixes');
    process.exit(1);
  }
});

console.log('✅ No manual vendor prefixes found');

// .husky/pre-push - Run tests before push
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

echo "🧪 Running tests before push..."

# Run full test suite
npm run test

# Run full linting (not just staged)
npm run lint

# Check build
npm run build

echo "✅ All pre-push checks passed!"

Example: Custom validation scripts

// scripts/validate-scss.js - Custom SCSS validation
const fs = require('fs');
const path = require('path');
const glob = require('glob');

// Custom rules beyond stylelint
const rules = {
  // Check for @import usage (should use @use)
  noImport: {
    pattern: /@import\s+['"][^'"]+['"]/g,
    message: 'Use @use instead of @import'
  },
  
  // Check for hardcoded colors (should use variables)
  noHardcodedColors: {
    pattern: /(?<!\/\/.*)(#[0-9a-fA-F]{3,6}|rgba?\([^)]+\))/g,
    exclude: /\$|@/,
    message: 'Use color variables instead of hardcoded values'
  },
  
  // Check for z-index values (should use map)
  zIndexMap: {
    pattern: /z-index:\s*\d+/g,
    message: 'Use z-index from $z-index map'
  }
};

// Validate files
const files = glob.sync('src/**/*.scss');
let hasErrors = false;

files.forEach(file => {
  const content = fs.readFileSync(file, 'utf8');
  const lines = content.split('\n');
  
  Object.entries(rules).forEach(([ruleName, rule]) => {
    lines.forEach((line, index) => {
      if (rule.pattern.test(line)) {
        if (!rule.exclude || !rule.exclude.test(line)) {
          console.error(
            `❌ ${file}:${index + 1} - ${rule.message}`
          );
          console.error(`   ${line.trim()}`);
          hasErrors = true;
        }
      }
    });
  });
});

if (hasErrors) {
  console.error('\n❌ SCSS validation failed!');
  process.exit(1);
}

console.log('✅ SCSS validation passed!');

// Add to package.json
{
  "scripts": {
    "validate:scss": "node scripts/validate-scss.js",
    "pre-commit": "npm run validate:scss && lint-staged"
  }
}

20.5 Continuous Integration and Deployment

Platform Configuration Steps Artifacts
GitHub Actions .github/workflows/*.yml Lint, test, build CSS files, reports
GitLab CI .gitlab-ci.yml Pipeline stages Build artifacts
CircleCI .circleci/config.yml Workflow jobs Compiled CSS
Jenkins Jenkinsfile Declarative pipeline Distribution files
Vercel/Netlify Build commands Auto-deployment Static assets

Example: GitHub Actions workflow

// .github/workflows/scss-ci.yml
name: SCSS CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main, develop]

jobs:
  lint-and-test:
    runs-on: ubuntu-latest
    
    strategy:
      matrix:
        node-version: [18.x, 20.x]
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      
      - name: Setup Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Run stylelint
        run: npm run lint:scss
      
      - name: Check Prettier formatting
        run: npm run format:check
      
      - name: Run custom SCSS validation
        run: npm run validate:scss
      
      - name: Build SCSS
        run: npm run build:scss
      
      - name: Run tests
        run: npm test
      
      - name: Upload build artifacts
        uses: actions/upload-artifact@v3
        with:
          name: css-build-${{ matrix.node-version }}
          path: dist/css/
      
      - name: Generate stylelint report
        if: always()
        run: npm run lint:scss:report
      
      - name: Upload lint report
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: stylelint-report
          path: stylelint-report.json
  
  size-check:
    runs-on: ubuntu-latest
    needs: lint-and-test
    
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20.x'
      
      - run: npm ci
      - run: npm run build:scss
      
      - name: Check bundle size
        uses: andresz1/size-limit-action@v1
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          build_script: build:scss
  
  deploy:
    runs-on: ubuntu-latest
    needs: [lint-and-test, size-check]
    if: github.ref == 'refs/heads/main'
    
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20.x'
      
      - run: npm ci
      - run: npm run build:scss
      
      - name: Deploy to production
        run: npm run deploy
        env:
          DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}

Example: GitLab CI pipeline

// .gitlab-ci.yml
image: node:20

cache:
  paths:
    - node_modules/

stages:
  - install
  - lint
  - build
  - test
  - deploy

install:
  stage: install
  script:
    - npm ci
  artifacts:
    paths:
      - node_modules/
    expire_in: 1 hour

lint:scss:
  stage: lint
  script:
    - npm run lint:scss
    - npm run format:check
  artifacts:
    reports:
      codequality: stylelint-report.json
    when: always

validate:scss:
  stage: lint
  script:
    - npm run validate:scss
  allow_failure: false

build:scss:
  stage: build
  script:
    - npm run build:scss
  artifacts:
    paths:
      - dist/css/
    expire_in: 1 week

test:unit:
  stage: test
  script:
    - npm run test
  coverage: '/Coverage: \d+\.\d+%/'
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml

deploy:production:
  stage: deploy
  script:
    - npm run deploy
  only:
    - main
  environment:
    name: production
    url: https://example.com
  when: manual

deploy:staging:
  stage: deploy
  script:
    - npm run deploy:staging
  only:
    - develop
  environment:
    name: staging
    url: https://staging.example.com

Example: Build optimization and caching

// package.json - Optimized build scripts
{
  "scripts": {
    "prebuild": "npm run clean",
    "build": "npm run build:scss && npm run optimize:css",
    "build:scss": "sass src/scss:dist/css --style=compressed --source-map",
    "build:scss:dev": "sass src/scss:dist/css --style=expanded --source-map",
    "watch:scss": "sass src/scss:dist/css --watch --style=expanded --source-map",
    "optimize:css": "npm run autoprefixer && npm run purgecss",
    "autoprefixer": "postcss dist/css/*.css --use autoprefixer -d dist/css",
    "purgecss": "purgecss --css dist/css/*.css --content 'src/**/*.html' --output dist/css",
    "clean": "rm -rf dist/css",
    "deploy": "npm run build && npm run upload",
    "upload": "aws s3 sync dist/css s3://my-bucket/css --cache-control max-age=31536000"
  },
  "devDependencies": {
    "sass": "^1.70.0",
    "postcss": "^8.4.0",
    "postcss-cli": "^11.0.0",
    "autoprefixer": "^10.4.0",
    "purgecss": "^5.0.0"
  }
}

// postcss.config.js
module.exports = {
  plugins: [
    require('autoprefixer')({
      overrideBrowserslist: [
        '> 1%',
        'last 2 versions',
        'not dead'
      ]
    }),
    require('cssnano')({
      preset: ['default', {
        discardComments: {
          removeAll: true
        },
        normalizeWhitespace: true
      }]
    })
  ]
};

// CI cache configuration
// GitHub Actions
- name: Cache dependencies
  uses: actions/cache@v3
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-

// GitLab CI
cache:
  key: ${CI_COMMIT_REF_SLUG}
  paths:
    - node_modules/
    - .npm/

20.6 Package Manager Integration (npm, yarn, pnpm)

Manager Installation Lock File Advantages
npm npm install package-lock.json Built-in, universal
Yarn Classic yarn install yarn.lock Faster, offline cache
Yarn Berry yarn install yarn.lock PnP, zero-installs
pnpm pnpm install pnpm-lock.yaml Disk efficient, strict
Bun bun install bun.lockb Fastest, built-in

Example: Complete package.json for SCSS project

{
  "name": "my-scss-project",
  "version": "1.0.0",
  "description": "SCSS-powered web application",
  "main": "index.js",
  "scripts": {
    "dev": "concurrently \"npm:watch:*\"",
    "watch:scss": "sass src/scss:dist/css --watch --style=expanded --source-map",
    "build": "npm run clean && npm run build:scss && npm run optimize",
    "build:scss": "sass src/scss:dist/css --style=compressed --no-source-map",
    "optimize": "postcss dist/css/*.css --use autoprefixer cssnano -d dist/css",
    "lint": "npm run lint:scss && npm run format:check",
    "lint:scss": "stylelint 'src/**/*.scss'",
    "lint:scss:fix": "stylelint 'src/**/*.scss' --fix",
    "format": "prettier --write 'src/**/*.{scss,js,json,md}'",
    "format:check": "prettier --check 'src/**/*.{scss,js,json,md}'",
    "test": "jest",
    "clean": "rm -rf dist/css",
    "prepare": "husky install",
    "size": "size-limit",
    "analyze": "sass src/scss:dist/css --style=expanded --embed-sources"
  },
  "dependencies": {},
  "devDependencies": {
    "sass": "^1.70.0",
    "sass-loader": "^14.0.0",
    "postcss": "^8.4.32",
    "postcss-cli": "^11.0.0",
    "autoprefixer": "^10.4.16",
    "cssnano": "^6.0.2",
    "stylelint": "^16.1.0",
    "stylelint-config-standard-scss": "^12.0.0",
    "stylelint-config-prettier-scss": "^1.0.0",
    "stylelint-scss": "^6.0.0",
    "stylelint-order": "^6.0.4",
    "prettier": "^3.1.1",
    "husky": "^8.0.3",
    "lint-staged": "^15.2.0",
    "concurrently": "^8.2.2",
    "size-limit": "^11.0.1",
    "@size-limit/file": "^11.0.1"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ],
  "size-limit": [
    {
      "path": "dist/css/main.css",
      "limit": "50 KB"
    }
  ],
  "engines": {
    "node": ">=18.0.0",
    "npm": ">=9.0.0"
  }
}

Example: pnpm workspace configuration

// pnpm-workspace.yaml
packages:
  - 'packages/*'
  - 'apps/*'

// package.json (root)
{
  "name": "monorepo",
  "private": true,
  "scripts": {
    "dev": "pnpm -r --parallel dev",
    "build": "pnpm -r build",
    "lint": "pnpm -r lint",
    "test": "pnpm -r test"
  },
  "devDependencies": {
    "sass": "^1.70.0",
    "stylelint": "^16.0.0",
    "prettier": "^3.0.0"
  }
}

// packages/design-system/package.json
{
  "name": "@company/design-system",
  "version": "1.0.0",
  "main": "dist/index.css",
  "scripts": {
    "dev": "sass src:dist --watch",
    "build": "sass src:dist --style=compressed",
    "lint": "stylelint 'src/**/*.scss'"
  },
  "devDependencies": {
    "sass": "workspace:*",
    "stylelint": "workspace:*"
  }
}

// apps/website/package.json
{
  "name": "@company/website",
  "version": "1.0.0",
  "dependencies": {
    "@company/design-system": "workspace:*"
  },
  "devDependencies": {
    "sass": "workspace:*"
  }
}

// .npmrc (pnpm configuration)
shamefully-hoist=false
strict-peer-dependencies=true
auto-install-peers=true
resolution-mode=highest

// Commands
pnpm install                    # Install all dependencies
pnpm -r build                   # Build all packages
pnpm --filter @company/website dev   # Run dev in specific package
pnpm -r --parallel dev          # Run dev in all packages

Example: Monorepo with Yarn workspaces

// package.json (root)
{
  "private": true,
  "workspaces": [
    "packages/*",
    "apps/*"
  ],
  "scripts": {
    "dev": "yarn workspaces foreach -pi run dev",
    "build": "yarn workspaces foreach -t run build",
    "lint": "yarn workspaces foreach run lint",
    "test": "yarn workspaces foreach run test"
  },
  "devDependencies": {
    "sass": "^1.70.0",
    "stylelint": "^16.0.0",
    "prettier": "^3.0.0",
    "lerna": "^8.0.0"
  }
}

// .yarnrc.yml (Yarn Berry)
nodeLinker: node-modules
yarnPath: .yarn/releases/yarn-4.0.2.cjs
enableGlobalCache: true

// Commands
yarn install                    # Install all dependencies
yarn workspace @company/design-system build
yarn workspaces foreach build   # Build all packages
yarn workspaces foreach -pi run dev  # Parallel interactive dev

// Alternative: Using Lerna with Yarn
// lerna.json
{
  "version": "independent",
  "npmClient": "yarn",
  "useWorkspaces": true,
  "packages": [
    "packages/*",
    "apps/*"
  ],
  "command": {
    "version": {
      "message": "chore(release): publish %s"
    }
  }
}

// Commands with Lerna
lerna bootstrap                 # Install dependencies
lerna run build                 # Run build in all packages
lerna run build --scope=@company/design-system
lerna publish                   # Publish packages

Development Workflow Best Practices

  • Linting: Use stylelint with SCSS plugins, enforce consistent naming and structure
  • Formatting: Prettier for automatic code formatting, integrate with editor and pre-commit
  • VS Code: Install SCSS IntelliSense, stylelint, and Prettier extensions for best DX
  • Git hooks: Use Husky + lint-staged to enforce quality before commits
  • CI/CD: Automate linting, testing, and building in GitHub Actions or GitLab CI
  • Package managers: Use pnpm for monorepos, enable caching and strict dependency resolution
  • Build optimization: Compress with Sass, add autoprefixer, purge unused CSS
  • Monorepo strategy: Share SCSS utilities across packages, use workspace dependencies
Note: A robust development workflow with automated linting, formatting, and testing catches errors early and maintains code quality. Integrate these tools into your editor and CI/CD pipeline for a seamless developer experience.