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.
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);
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.
Awesome, thank you!
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…
Thank you, I didn’t know that!
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