SASS-only Material Angular Palette generator

With my job, I often need to replicate projects from a template based on Angular Material. When I do that, one of the first things that I usually need to change is the color scheme.

Angular Material’s color scheme is defined by two palettes: primary and accent. These two palettes define a range of colors used by all components.

There are many tools available online to generate such palettes. My personal favourite is Material Design Color Generator (also available on GitHub). This tool includes a code generator that automatically creates a SASS list in Angular Material’s accepted format.

I based my SASS color palette generator on Mikel Bitson‘s code. This is a simple SASS translation that makes it easier to adjust colors directly from your code. 

So, without further ado, here’s the code.

mat-palette-gen.scss

SCSS
@use 'sass:math';
@use 'sass:map';
 
$values: (50, 100, 200, 300, 400, 500, 600, 700, 800, 900, A100, A200, A400, A700);
 
@function createPalette($color) {
  $white: #fff;
  $black: #000;
  $baseDark: multiply($color, $color);
 
  $palette: (
    50 : mix($color, $white, 12%),
    100 : mix($color, $white, 30%),
    200 : mix($color, $white, 50%),
    300 : mix($color, $white, 70%),
    400 : mix($color, $white, 85%),
    500 : mix($color, $white, 100%),
    600 : mix($color, $baseDark, 87%),
    700 : mix($color, $baseDark, 70%),
    800 : mix($color, $baseDark, 54%),
    900 : mix($color, $baseDark, 25%),
    A100 : lighten(saturate(mix($black, $baseDark, 15%), 80%), 65%),
    A200 : lighten(saturate(mix($black, $baseDark, 15%), 80%), 55%),
    A400 : lighten(saturate(mix($black, $baseDark, 15%), 100%), 45%),
    A700 : lighten(saturate(mix($black, $baseDark, 15%), 100%), 40%)
  );
 
  $contrast: ();
  @each $v in $values {
    $contrast: map.merge($contrast, ($v: getContrast(map_get($palette, $v))))
  }
 
  $palette: map.merge($palette, (contrast: $contrast));
 
  @return $palette;
}
 
 
@function multiply($rgb1, $rgb2) {
  $r: math.floor(red($rgb1) * red($rgb2) / 255);
  $g: math.floor(green($rgb1) * green($rgb2) / 255);
  $b: math.floor(blue($rgb1) * blue($rgb2) / 255);
  @return rgb($r, $g, $b);
}
 
@function getBrightness($color) {
  @return (red($color) * 299 + green($color) * 587 + blue($color) * 114) / 1000;
}
 
@function isLight($color) {
  @return getBrightness($color) >= 128;
}
 
@function getContrast($color) {
  @if isLight($color) {
    @return #000;
  } @else {
    @return #fff;
  }
}

Usage in style.scss

SCSS
@import '~@angular/material/theming';
@include mat-core();
@import 'mat-palette-gen.scss';

$primary-color: #9c27b0;
$accent-color: #2196f3;

$primary-palette: createPalette($primary-color);
$accent-palette: createPalette($accent-color);

$warn: mat-palette($mat-red);
$primary: mat-palette($primary-palette);
$accent: mat-palette($accent-palette);

// Pick one
$theme: mat-dark-theme($primary, $accent, $warn);
// $theme: mat-light-theme($primary, $accent, $warn);

@include angular-material-theme($theme);

Result

5 thoughts on “SASS-only Material Angular Palette generator”

  1. After almost a day looking for a way to build a real custom theme for my Angular app, i.e. using custom color codes, I found your post and was able to import your code in my dev environment and make it run.
    For now results are fine, thanks a lot.

    Reply
  2. Your code only works if it is compiled with dart-sass, since it’s AFAIK the only compiler supporting the @use command at the moment. (https://github.com/madskristensen/WebCompiler/issues/441)

    However it’s easily possible to make it work for other compilers (like node-sass) by removing the ‘@use’ includes and replace ‘map.merge’ with ‘map-merge’ and ‘math.floor’ with simply ‘floor’. Hope I can help someone struggling to get it work in their setup…

    Reply
  3. Grazie mille, Luca! Questa soluzione ha cambiato la mia vita al lavoro. 🙂
    This greatly simplified my issues with sass in my project, and gave us a streamlined way to move forward on other projects.

    Spero tutto va bene per voi.
    -Jennifer

    Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.