SCSS Color Management and Theme Systems

1. Color Palette Maps ($colors) 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);
}

2. Color Scheme Generation (sass:color functions)

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'); }
}

3. Dark Mode (@media prefers-color-scheme) 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);
  }
}

4. Accessibility Color Contrast (WCAG AA/AAA) 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;
}

5. Dynamic Color Manipulation (adjust(), scale())

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);
}

6. Design Tokens 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.