使用CSS变量创建角形材质主题

问题描述:

我正在研究一个需要在运行时主题化的项目.因此,我创建了一个将SCSS变量与CSS变量结合在一起的主题系统. 这就是它的样子.

I am 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%);

虽然我的自定义组件可以很好地工作,但我很难使它与Material Design主题系统一起工作.

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

我的想法是,我将按照Angular材质文档中的说明创建主题,而不是使用静态颜色,而是使用SCSS变量.这就是我的theme.scss文件的样子.

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);

我得到一个错误:

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

大概是因为Angular Material mixin期望的是color而不是hsl()的值.

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

所以我的问题是如何使用运行时CSS变量创建自定义材质主题?

如果升级到@ angular/material,则7.3.4 CSS变量将大部分可用.只有使用不透明性的涟漪和其他东西才需要稍作修复.我将rgba()用于我的项目,但它也适用于hsla()

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()

包括此内容:

@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));
}

紧接在

@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);

然后,您需要将sass函数中的str-index($ color,',')更改为在字符串中找到最后一个','的内容.不幸的是,我的无礼知识只涵盖了最低限度的知识,我不知道该怎么做:/

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 :/