Material Theme Creator

GitHub  |  Demo page

Create a custom theme from one color in real time. It's pure CSS, without JavaScript

Hue

220

Saturation

80

Lightness

60

Contrast threshold

65%
65
50
var(--my-theme-50)

hsla(
  var(--my-theme-50)-h,
  var(--my-theme-50)-s,
  var(--my-theme-50)-l,
  100%,
)
100
var(--my-theme-100)

hsla(
  var(--my-theme-100)-h,
  var(--my-theme-100)-s,
  var(--my-theme-100)-l,
  100%,
)
200
var(--my-theme-200)

hsla(
  var(--my-theme-200)-h,
  var(--my-theme-200)-s,
  var(--my-theme-200)-l,
  100%,
)
300
var(--my-theme-300)

hsla(
  var(--my-theme-300)-h,
  var(--my-theme-300)-s,
  var(--my-theme-300)-l,
  100%,
)
400
var(--my-theme-400)

hsla(
  var(--my-theme-400)-h,
  var(--my-theme-400)-s,
  var(--my-theme-400)-l,
  100%,
)
500
var(--my-theme-500)

hsla(
  var(--my-theme-500)-h,
  var(--my-theme-500)-s,
  var(--my-theme-500)-l,
  100%,
)
600
var(--my-theme-600)

hsla(
  var(--my-theme-600)-h,
  var(--my-theme-600)-s,
  var(--my-theme-600)-l,
  100%,
)
700
var(--my-theme-700)

hsla(
  var(--my-theme-700)-h,
  var(--my-theme-700)-s,
  var(--my-theme-700)-l,
  100%,
)
800
var(--my-theme-800)

hsla(
  var(--my-theme-800)-h,
  var(--my-theme-800)-s,
  var(--my-theme-800)-l,
  100%,
)
900
var(--my-theme-900)

hsla(
  var(--my-theme-900)-h,
  var(--my-theme-900)-s,
  var(--my-theme-900)-l,
  100%,
)
A100
var(--my-theme-A100)

hsla(
  var(--my-theme-A100)-h,
  var(--my-theme-A100)-s,
  var(--my-theme-A100)-l,
  100%,
)
A200
var(--my-theme-A200)

hsla(
  var(--my-theme-A200)-h,
  var(--my-theme-A200)-s,
  var(--my-theme-A200)-l,
  100%,
)
A400
var(--my-theme-A400)

hsla(
  var(--my-theme-A400)-h,
  var(--my-theme-A400)-s,
  var(--my-theme-A400)-l,
  100%,
)
A700
var(--my-theme-A700)

hsla(
  var(--my-theme-A700)-h,
  var(--my-theme-A700)-s,
  var(--my-theme-A700)-l,
  100%,
)

Contents

How it works

We use CSS Custom Properties and HSL color space for dynamic theme colors’ calculation.

:root {
  --primary-h: 260;
  --primary-s: 80%;
  --primary-l: 40%;
  --primary: hsl( var(--primary-h), var(--primary-s), var(--primary-l) );
}

We have already created a color consisting of H, S and L components of the HSL color space. But how can we create the whole theme palette? We need to do some calculations for this.

:root {
  --primary-400: hsl(
                      calc( var(--primary-h) * var(--h-400) ),
                      calc( var(--primary-s) * var(--s-400) ),
                      calc( var(--primary-l) * var(--l-400) )
                  );
  --primary-500: hsl(
                      calc( var(--primary-h) * var(--h-500) ),
                      calc( var(--primary-s) * var(--s-500) ),
                      calc( var(--primary-l) * var(--l-500) )
                  );
}

In fact, the code is a bit more complicated, but this piece of code is enough to understand the algorithm.

How to use Material Theme Creator

1. Pure CSS use

You can download your theme by clicking on the button "Download theme" which is located above. Then you should include it to your page in any convenient way. For example:

<link href="./my-theme.css" rel="stylesheet">

After that you can create the second theme style:

.second-theme {
   --my-theme-h: 190;
   --my-theme-s: 80;
   --my-theme-l: 40;
   --my-theme-contrast-threshold: 50%;
}

And you can apply the theme with some button:

const changeThemeButton = document.querySelector('button.change-theme-bth');
changeThemeButton.addEventListener('click', () => {
    document.documentElement.classList.toggle('second-theme');
});

How can you use theme on your elements? 14 theme colors will be available for you. For each of these colors you will have access to one contrasting color. See example:

 button {
     background-color: var(--my-theme);
     color: var(--my-theme-contrast);
     &:hover {
         background-color: var(--my-theme-700);
         color: var(--my-theme-700-contrast);
     }
 }

How can we set transparency of the color? You can adjust it yourself:

     background-color: hsla(
                          var(--my-theme-500-h),
                          var(--my-theme-500-s),
                          var(--my-theme-500-l),
                          62% /* alpha */
                       );

2. Use with SCSS

You can have more options to manage the theme if you use SCSS.
Installation:

npm install material-theme-creator

Use:

@import "~material-theme-creator/core";

// root variables initializing
@include mtc-init();

:root {
  // Creating a theme based on some color
  // Passing arguments to the mixin:
  //   1. theme name
  //   2. some color
  //   3. contrast threshold (for fonts)
  @include mtc-create-variables-from-color('primary', #cc3300, 50%);
}

.second-theme {
  @include mtc-update-theme('primary', #6200ee, 55%);
}

button {
  color: mtc-color-contrast('primary');
  background-color: mtc-color('primary');
  &:hover {
    color: mtc-color-contrast('primary', 700);
    background-color: mtc-color('primary', 700, 92%);
  }
}

3. Use with  Angular Material

You can use ngx-mtc module to convert Angular Material themes to use CSS Custom Properties.

3.1 Setup
@import "~material-theme-creator/ngx-mtc";
@import '~@angular/material/theming';

@include mat-core();
@include ngx-mtc-init();

$primary-map: ngx-mtc-create-theme-map('primary');
$accent-map: ngx-mtc-create-theme-map('accent');
$warn-map: ngx-mtc-create-theme-map('warn');

We have two options for creating of themes:

Recommended

3.2 Creating theme from one color

In this case, each theme will consist of just a few lines of code.

:root {
  --is-dark-theme: 1; // Is dark theme? 1 or 0;
  @include ngx-mtc-theme-base(); // Creates base colors

  // Creates theme colors
  @include ngx-mtc-create-variables-from-color('primary', #009688, 38%);
  @include ngx-mtc-create-variables-from-color('accent', #2196f3, 57%);
  @include ngx-mtc-create-variables-from-color('warn', #f44336, 62%);
}

// Creates Angular Material Theme
@include angular-material-theme(
  ngx-mtc-custom-theme(
    mat-palette($primary-map),
    mat-palette($accent-map),
    mat-palette($warn-map)
  )
);

The second theme code:

.second-theme {
  --is-dark-theme: 0;
  @include ngx-mtc-update-theme('primary', #142148, 45%);
  @include ngx-mtc-update-theme('accent', #658e14, 50%);
  @include ngx-mtc-update-theme('warn', #750101, 50%);
}

Not recommended

3.3 Converting true Angular Material themes to using CSS Custom Properties

The angular-material-theme() mixin generates a lot of CSS code for each theme, so you shouldn't use this method.

:root {
  @include ngx-mtc-create-variables-from-map('primary', $mat-teal);
  @include ngx-mtc-create-variables-from-map('accent', $mat-deep-purple);
  @include ngx-mtc-create-variables-from-map('warn', $mat-red);
}

// Light theme
@include angular-material-theme(
           mat-light-theme(
             mat-palette($primary-map),
             mat-palette($accent-map),
             mat-palette($warn-map)
           )
         );

// Dark theme
// @include angular-material-theme(
//            mat-dark-theme(
//              mat-palette($primary-map),
//              mat-palette($accent-map),
//              mat-palette($warn-map)
//            )
//          );

In this case the second theme is recommended to be moved into the external CSS file and included as follows:

<link href="./second-theme.css" rel="stylesheet">

The second theme code:

// second-theme.scss
:root {
  @include ngx-mtc-update-theme('primary', #142148, 45%);
  @include ngx-mtc-update-theme('accent', #658e14, 50%);
  @include ngx-mtc-update-theme('warn', #750101, 50%);
}


// If both themes are light or dark, then you can skip
//   the following part of code to save the user's traffic

// Light theme
// @include angular-material-theme(
//            mat-light-theme(
//              mat-palette($primary-map),
//              mat-palette($accent-map),
//              mat-palette($warn-map)
//            )
//          );

// Dark theme
@include angular-material-theme(
           mat-dark-theme(
             mat-palette($primary-map),
             mat-palette($accent-map),
             mat-palette($warn-map)
           )
         );

3.4 How to use it

Use standard Angular material mat-color and mat-contrast mixins to extract specific colors from the theme.

button {
  color: mat-contrast($primary-map, 500);
  background-color: mat-color($primary-map, 500);
  &:hover {
    color: mat-contrast($primary-map, 700);
    background-color: mat-color($primary-map, 700, 92%);
  }
}

Testing [@mixin mtc-create-variables-from-color]

50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700
50100200300400500600700800900A100A200A400A700