SASS/SCSS

Maps: Creating & Advanced Operations

20 min Lesson 16 of 30

Introduction to SASS Maps

SASS maps are one of the most powerful data structures in SASS. They allow you to store key-value pairs, similar to objects in JavaScript or dictionaries in Python. Maps are incredibly useful for organizing related data and creating scalable systems for colors, breakpoints, spacing, and more.

What Are SASS Maps?

A map is a collection of key-value pairs enclosed in parentheses. Each key must be unique and is separated from its value by a colon. Multiple pairs are separated by commas:

Basic Map Syntax

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

$breakpoints: (
  xs: 0,
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px
);
Note: Maps must be enclosed in parentheses. The syntax is $map-name: (key1: value1, key2: value2). You can use any data type as values, including strings, numbers, colors, lists, and even other maps.

Why Use Maps?

Maps provide several advantages over traditional variables:

  • Organization: Group related values together logically
  • Scalability: Easy to add, remove, or modify values
  • Iteration: Loop through map entries with @each
  • Maintainability: Single source of truth for related data
  • Flexibility: Create complex data structures with nested maps

Accessing Map Values

Using map-get() Function

The map-get() function retrieves a value from a map by its key:

Accessing Map Values

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

.button {
  background-color: map-get($colors, primary); // #3498db

  &:hover {
    background-color: darken(map-get($colors, primary), 10%);
  }
}

.alert-danger {
  color: map-get($colors, danger); // #e74c3c
  border-color: map-get($colors, danger);
}

Modern map.get() Syntax

With the SASS module system, you can use map.get() from the map module:

Using map.get() with @use

@use "sass:map";

$colors: (
  primary: #3498db,
  secondary: #2ecc71
);

.card {
  background: map.get($colors, primary);
  border: 1px solid map.get($colors, secondary);
}
Tip: The map.get() syntax is the modern, module-based approach. If you're using the @use rule, prefer map.get() over map-get().

Checking for Keys

map-has-key() Function

Before accessing a map value, you might want to check if a key exists:

Checking Key Existence

$theme: (
  primary: #3498db,
  secondary: #2ecc71
);

@if map-has-key($theme, primary) {
  .btn-primary {
    background: map-get($theme, primary);
  }
}

@if not map-has-key($theme, tertiary) {
  @warn "Tertiary color is not defined in theme";
}

Safe Access Pattern

Create a safe getter function that returns a fallback value:

Safe Map Access Function

@function get-color($key, $fallback: #000) {
  $colors: (
    primary: #3498db,
    secondary: #2ecc71
  );

  @if map-has-key($colors, $key) {
    @return map-get($colors, $key);
  }

  @warn "Color '#{$key}' not found. Using fallback.";
  @return $fallback;
}

.element {
  color: get-color(primary); // #3498db
  background: get-color(tertiary, #ccc); // #ccc with warning
}

Getting Keys and Values

map-keys() Function

Extract all keys from a map as a list:

Extracting Map Keys

$spacing: (
  xs: 0.25rem,
  sm: 0.5rem,
  md: 1rem,
  lg: 1.5rem,
  xl: 3rem
);

$spacing-keys: map-keys($spacing);
// Result: (xs, sm, md, lg, xl)

@debug $spacing-keys; // Output in console

map-values() Function

Extract all values from a map as a list:

Extracting Map Values

$font-sizes: (
  small: 0.875rem,
  normal: 1rem,
  large: 1.25rem
);

$sizes: map-values($font-sizes);
// Result: (0.875rem, 1rem, 1.25rem)

// Find minimum font size
$min-size: min($sizes...);

Merging Maps

map-merge() Function

Combine two maps into a new map. If keys overlap, the second map's values take precedence:

Merging Maps

$default-colors: (
  primary: #3498db,
  secondary: #2ecc71,
  text: #333
);

$custom-colors: (
  primary: #e74c3c,    // Override
  accent: #9b59b6      // New key
);

$theme: map-merge($default-colors, $custom-colors);
// Result:
// (
//   primary: #e74c3c,     // Overridden
//   secondary: #2ecc71,
//   text: #333,
//   accent: #9b59b6       // Added
// )

.app {
  background: map-get($theme, primary); // #e74c3c
}

Merging Multiple Maps

Chain map-merge() calls to combine multiple maps:

Chaining Map Merges

$base: (
  primary: blue
);

$theme-light: (
  bg: white,
  text: black
);

$theme-dark: (
  bg: black,
  text: white
);

$final-light: map-merge(map-merge($base, $theme-light), (
  accent: yellow
));
// Result: (primary: blue, bg: white, text: black, accent: yellow)

Removing Keys

map-remove() Function

Create a new map with specified keys removed:

Removing Map Keys

$all-colors: (
  primary: #3498db,
  secondary: #2ecc71,
  danger: #e74c3c,
  warning: #f39c12,
  deprecated-color: #ccc
);

$active-colors: map-remove($all-colors, deprecated-color);
// Result: Map without deprecated-color

// Remove multiple keys
$main-colors: map-remove($all-colors, warning, deprecated-color);
Warning: Map functions like map-remove() and map-merge() do not modify the original map. They return a new map. Maps in SASS are immutable.

Nested Maps

Creating Nested Map Structures

Maps can contain other maps as values, allowing you to create complex data structures:

Nested Maps Example

$theme: (
  colors: (
    primary: #3498db,
    secondary: #2ecc71,
    shades: (
      light: #5dade2,
      dark: #2874a6
    )
  ),
  typography: (
    font-family: "Inter, sans-serif",
    sizes: (
      small: 0.875rem,
      normal: 1rem,
      large: 1.25rem
    )
  ),
  spacing: (
    xs: 0.25rem,
    sm: 0.5rem,
    md: 1rem
  )
);

Accessing Nested Map Values

Access nested values by chaining map-get() calls:

Accessing Nested Values

$theme: (
  colors: (
    primary: #3498db,
    shades: (
      light: #5dade2,
      dark: #2874a6
    )
  )
);

// Access nested value
$primary-light: map-get(map-get(map-get($theme, colors), shades), light);

// Create a helper function for easier access
@function theme-get($keys...) {
  $value: $theme;
  @each $key in $keys {
    $value: map-get($value, $key);
  }
  @return $value;
}

.button {
  background: theme-get(colors, primary); // #3498db

  &:hover {
    background: theme-get(colors, shades, dark); // #2874a6
  }
}
Tip: For deeply nested maps, create helper functions to simplify access. This makes your code more readable and maintainable.

Iterating Over Maps

Using @each with Maps

Loop through map entries to generate CSS dynamically:

Basic Map Iteration

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

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

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

// Generated CSS:
// .btn-primary { background-color: #3498db; ... }
// .btn-success { background-color: #2ecc71; ... }
// .btn-danger { background-color: #e74c3c; ... }
// .btn-warning { background-color: #f39c12; ... }

Advanced Iteration Examples

Generating Utility Classes

$spacing-scale: (
  0: 0,
  1: 0.25rem,
  2: 0.5rem,
  3: 0.75rem,
  4: 1rem,
  5: 1.5rem,
  6: 2rem
);

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

// Generate margin utilities
@each $key, $value in $spacing-scale {
  .m-#{$key} { margin: $value; }
  .p-#{$key} { padding: $value; }

  @each $side-key, $side-value in $sides {
    .m#{$side-key}-#{$key} { margin-#{$side-value}: $value; }
    .p#{$side-key}-#{$key} { padding-#{$side-value}: $value; }
  }
}

// Generated: .m-0, .m-1, .mt-2, .pr-3, etc.

Real-World Use Cases

1. Theme Color System

Complete Theme System

$theme-colors: (
  primary: (
    base: #3498db,
    light: #5dade2,
    dark: #2874a6,
    contrast: #fff
  ),
  secondary: (
    base: #2ecc71,
    light: #58d68d,
    dark: #229954,
    contrast: #fff
  ),
  neutral: (
    base: #95a5a6,
    light: #d5dbdb,
    dark: #566573,
    contrast: #fff
  )
);

@function theme-color($color-name, $variant: base) {
  @return map-get(map-get($theme-colors, $color-name), $variant);
}

.btn-primary {
  background: theme-color(primary);
  color: theme-color(primary, contrast);

  &:hover {
    background: theme-color(primary, dark);
  }
}

2. Responsive Breakpoints

Breakpoint System

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

@function breakpoint($name) {
  @if map-has-key($breakpoints, $name) {
    @return map-get($breakpoints, $name);
  }
  @warn "Breakpoint '#{$name}' not found";
  @return null;
}

@mixin respond-above($name) {
  $breakpoint: breakpoint($name);
  @if $breakpoint {
    @media (min-width: $breakpoint) {
      @content;
    }
  }
}

.container {
  width: 100%;

  @include respond-above(md) {
    max-width: 720px;
  }

  @include respond-above(lg) {
    max-width: 960px;
  }

  @include respond-above(xl) {
    max-width: 1140px;
  }
}

3. Z-Index Scale

Z-Index Management

$z-layers: (
  base: 1,
  dropdown: 100,
  sticky: 200,
  fixed: 300,
  modal-backdrop: 400,
  modal: 500,
  popover: 600,
  tooltip: 700,
  toast: 800
);

@function z($layer) {
  @if map-has-key($z-layers, $layer) {
    @return map-get($z-layers, $layer);
  }
  @warn "Z-index layer '#{$layer}' not found";
  @return 1;
}

.dropdown-menu {
  z-index: z(dropdown);
}

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

.tooltip {
  z-index: z(tooltip);
}

4. Spacing System

Consistent Spacing

$spacing: (
  none: 0,
  xs: 0.25rem,
  sm: 0.5rem,
  md: 1rem,
  lg: 1.5rem,
  xl: 2rem,
  xxl: 3rem,
  xxxl: 4rem
);

@each $name, $value in $spacing {
  .gap-#{$name} { gap: $value; }
  .space-x-#{$name} > * + * { margin-left: $value; }
  .space-y-#{$name} > * + * { margin-top: $value; }
}

// Custom spacing function
@function space($size) {
  @return map-get($spacing, $size);
}

.card {
  padding: space(md);
  margin-bottom: space(lg);
}

Exercise 1: Color Palette System

Create a comprehensive color palette system using maps:

  1. Define a $colors map with primary, secondary, success, danger, warning, and info colors
  2. Each color should have a nested map with: base, light, lighter, dark, darker values
  3. Create a color() function that accepts color name and variant
  4. Generate button classes for each color using @each
  5. Each button should have hover states using the dark variant

Exercise 2: Responsive Typography

Build a responsive typography system:

  1. Create a $font-sizes map with heading levels (h1-h6) and body text
  2. Each key should contain a nested map with sizes for mobile, tablet, and desktop
  3. Create a mixin that generates responsive font sizes using @media queries
  4. Apply the mixin to generate styles for all heading elements
  5. Add line-height and font-weight to the nested map structure

Exercise 3: Grid System with Maps

Create a flexible grid system using maps:

  1. Define a $grid-columns map with column counts: 1, 2, 3, 4, 6, 12
  2. Create a $grid-breakpoints map (xs, sm, md, lg, xl)
  3. Generate column classes: .col-1, .col-2, etc.
  4. Generate responsive classes: .col-md-6, .col-lg-4, etc.
  5. Add gap utilities using a $grid-gaps map

Summary

In this lesson, you learned:

  • How to create and use SASS maps for organizing data
  • Accessing map values with map-get() and map.get()
  • Checking for keys with map-has-key()
  • Extracting keys and values with map-keys() and map-values()
  • Merging maps with map-merge() for configuration systems
  • Removing keys with map-remove()
  • Creating and accessing nested maps for complex data
  • Iterating over maps with @each to generate CSS
  • Real-world applications: theme systems, breakpoints, z-index scales, spacing

Maps are essential for building scalable, maintainable SASS architectures. They enable you to create sophisticated design systems, manage complex configurations, and generate repetitive CSS patterns efficiently. Master maps and you'll unlock the full power of SASS for large-scale projects.