Generate CSS classes and variables from Angular Material Palette

In this blog, we should learn about generating CSS classes and variables from Angular Material Palette. It can also be used to strengthen some SCSS skills.

✅ Generate CSS classes from Angular Material Palette

✅ Generate CSS variables from Angular Material Palette

🗎 Source Code: https://github.com/vugar005/youtube-webapp-turborepo

💎 Live Demo: https://youtube.vugar.app

Why?🤔

 Let's say we have some HTML elements like this:

<h1> Product Title </h1>
<h2> Product Subtitle </h2>

In order to change the color of elements, usually, we would do it like below: 😕

@import './palette';

h1 {
    color: map-get($app-primary, 60);
}

h2 {
    color: map-get($app-accent, 50);
}

 Well as you see, it is already verbose 😕. Just for adding color, we have to import the palette and use a map-get function.

Solution: 🛠

 What if we would able to style HTML elements just by adding classes like the below? ⬇️

<h1 class="app-primary-60"> Product Title </h1>
<h2 class="app-accent-50"> Product Subtitle </h2>

 or even by using CSS variables? 🙂

h1 {
    color: var(--app-primary-60);
}

h2 {
    color: var(--app-accent-50);
}

 In order to achieve this, we can generate CSS classes and CSS variables from Angular Material Palette. The palette is actually a SCSS map which is like a Map object in Javascript.

 Assume we have a palette like the below:

@use 'sass:map';
@import '@angular/material/theming';

$app-primary: (
  10: #c5e4ff,
  20: #9fd2ff,
  30: #78c0ff,
  40: #5bb3ff,
  50: #3ea5ff,
  60: #389dff,
  ...
);

$app-accent: (
  70: #91a4a0,
  50: #b0bebb,
  10: #eff2f1,
  contrast: (
    10: #000,
    50: #fff,
    70: #fff,
  ),
);

$app-warning: (
  dark: #ffa02f,
  base: #ffcf97,
  contrast: (
    90: #fff,
    50: #fff,
  ),
);

 So let's add a new file called generate-material-classes.scss which would include the below code.

Note: we are going to simplify below code later in this post 🚀.

@use '../palette';

@mixin app-primary-colors {
  $colors-map: ();

  @each $key, $value in $app-primary {
    @if $key !=contrast {
      .app-primary-#{$key} {
        color: map-get($app-primary, $key);
      }

    $map: ();
    $map: map-merge($map, ($key: $value));
    $colors-map: map-merge($colors-map, $map);
    }
  }

  :root {
    @each $key, $value in $colors-map {
      --app-primary-#{$key}: #{$value};
    }
  }
}

@mixin app-accent-colors {
  $colors-map: ();

  @each $key, $value in $app-accent {
    @if $key !=contrast {
      .app-accent-#{$key} {
        color: map-get($app-accent, $key);
      }

    $map: ();
    $map: map-merge($map, ($key: $value));
    $colors-map: map-merge($colors-map, $map);
    }
  }

  :root {
    @each $key, $value in $colors-map {
      --app-accent-#{$key}: #{$value};
    }
  }
}

@mixin app-warning-colors {
  $colors-map: ();

  @each $key, $value in $app-warning {
    @if $key !=contrast {
      .app-warning-#{$key} {
        color: map-get($app-warning, $key);
      }

    $map: ();
    $map: map-merge($map, ($key: $value));
    $colors-map: map-merge($colors-map, $map);
    }
  }

  :root {
    @each $key, $value in $colors-map {
      --app-warning-#{$key}: #{$value};
    }
  }
}


@mixin app-generate-color-classes {
  @include app-primary-colors();
  @include app-accent-colors();
  @include app-warning-colors();
}

 Basically, we iterate over key/values for each palette and add CSS classes. We also append those key/values to an array which we use for root to generate CSS variables.

 Now in styles.scss file:

@import 'generate-material-colors';
@include generate-material-classes();

 Now we can use classes like app-primary-60 and so on.

 Also, let's confirm the solution by inspecting CSS variables via devTools:

 Beautiful, is not it? 😎

Optimized solution: 🚀

 As you see we add 3 different mixins for generating primary, accent, and warning colors in the above solution 😕. So let's simplify this by using a single function with parameters:

@use '../palette';

@mixin generateColors($prefix, $palette) {
  $colors-map: ();

  @each $key, $value in $palette {
    @if $key !=contrast {
      .app-#{$prefix}-#{$key} {
        color: map-get($palette, $key);
      }

    $map: ();
    $map: map-merge($map, ($key: $value));
    $colors-map: map-merge($colors-map, $map);
    }
  }

  :root {
    @each $key, $value in $colors-map {
      --app-#{$prefix}-#{$key}: #{$value};
    }
  }
}

@mixin generate-material-classes {
   @include generateColors(primary, $youtube-primary);
   @include generateColors(accent, $youtube-accent);
   @include generateColors(warning, $youtube-warning);
}

 That's all hope you enjoyed it and found it useful. Thanks for reading.🍍

 🗎 Source Code: https://github.com/vugar005/youtube-webapp-turborepo