Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create angular material theme with CSS variables

I'm working on a project that requires to be themeable at runtime. So I created a theme system that combines SCSS variable with CSS Variables. This is how it looks.

:root {
  --primary-color: 196;
}


// Primary
$primary-100: hsl(var(--primary-color), 90%, 98%);
$primary-400: hsl(var(--primary-color), 90%, 65%);
$primary-main: hsl(var(--primary-color), 90%, 50%);
$primary-700: hsl(var(--primary-color), 90%, 30%);
$primary-900: hsl(var(--primary-color), 90%, 10%);

While this works amazingly with my custom components, I'm having a hard time making it work with the Material design theme system.

My thinking was that I will create the theme as explained in the Angular material docs, and instead of using static colors, I will use my SCSS variables. this is how my theme.scss file looks like.

@import '~@angular/material/theming';
@import 'var.scss';

@include mat-core();

$shop-primary: (
  50: $primary-100,
  100: $primary-100,
  200: $primary-200,
  300: $primary-300,
  400: $primary-400,
 // ..... all other colors
  contrast: (
    50: $black-87-opacity,
    100: $black-87-opacity,
    200: $black-87-opacity,
     // ..... all other colors
  )
);


$shop-app-primary: mat-palette($shop-primary);
$shop-app-accent:  mat-palette($shop-primary);
$shop-app-warn: mat-palette($shop-primary);


$shop-app-theme: mat-light-theme($shop-app-primary, $shop-app-accent, $shop-app-warn);

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

And I'm getting an error:

 Argument `$color` of `rgba($color, $alpha)` must be a color

Presumingly because the Angular Material mixin is expecting a color and not a hsl() value.

So my question is how would I be able to create a custom material theme with runtime CSS variables?

like image 603
David Genger Avatar asked Feb 08 '19 15:02

David Genger


People also ask

How do I create a custom material theme?

To do so, open the Settings and navigate to Appearance & Behavior → Material Theme UI → Custom Theme. Once you're done customizing your colors, you'll need to select Custom Theme or Light Custom Theme from the Theme Switcher to see your colors in action. Enjoy!

Can you change SCSS variable value dynamically?

CSS Variables to the Rescue CSS variables is a standard which enables you to have variables in CSS. SCSS is compiled to CSS during compile time, and SCSS variables are replaced with resolved value during compile time, which means there is no way to change the variable during run time.

Can we customize angular material?

Angular Material's theming system lets you customize color and typography styles for components in your application. The theming system is based on Google's Material Design specification. This document describes the concepts and APIs for customizing colors. For typography customization, see Angular Material Typography.

Can I change angular material theme?

it's very easy to create a custom angular material theme. This will allow you to specify primary, accent and warning colors that will be used on Angular Material components. Your custom theme will be a Sass file and in our case, we'll call it theme. scss and place it in our app's /src folder.


1 Answers

If you upgrade to @angular/material 7.3.4 CSS Variables will mostly work. Only riples and other stuff that uses opacity will need a little fix. I use rgba() for my project, but it should also work for hsla()

Include this:

@function mat-color($palette, $hue: default, $opacity: null) {
    @if type-of($hue) == number and $hue >= 0 and $hue <= 1 {
        @return mat-color($palette, default, $hue);
    }

    $color: map-get($palette, $hue);

    @if (type-of($color) != color) {
        @if ($opacity == null){
            @return $color;
        }

        // Here is the change from the original function:
        // If the $color resolved to something different from a color, we assume it is a CSS variable
        // in the form of rgba(var(--rgba-css-var),a) and replace the 'a' value.
        @return #{str-slice($color, 0, str-index($color, ',')) + $opacity + ')'};
    }

    @return rgba($color, if($opacity == null, opacity($color), $opacity));
}

directly after:

@import '~@angular/material/theming';

and define your colors like this:

--primary-color-50-parts: 0,158,224;
// ... all other colors

$color-primary: (
    50: rgba(var(--primary-color-50-parts), 1),
    // ... all other colors
);

if you define your colors in the map like this:

50: hsla(var(--primary-color), 90%, 98%, 1);

then you need to change str-index($color, ',') in the sass function to something that finds the last ',' in the string. Unfortunatelly my sass knowledge covers only the bare minimum and I don't know how to do that :/

like image 145
Benedikt Langer Avatar answered Sep 28 '22 14:09

Benedikt Langer