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

时间:2019-02-08 15:35:52

标签: css angular sass angular-material

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

: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主题系统一起工作。

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

@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()的值。

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

5 个答案:

答案 0 :(得分:4)

如果您升级到@ angular / material 7.3.4,则CSS变量将大部分可用。只有使用不透明性的涟漪和其他东西才需要稍作修复。我将rgba()用于我的项目,但它也适用于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';

并定义您的颜色,如下所示:

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

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

如果您在地图中这样定义颜色:

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

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

答案 1 :(得分:2)

我创建了一个little library,以简化此操作。

您可以像这样使用它:

  1. 安装:

    npm i angular-material-css-vars -S
    
  2. 然后从主样式表文件中删除所有现有的@import '~@angular/material/theming';

  3. 将其添加到主样式表中:

    @import '~angular-material-css-vars/main';
    @include initMaterialCssVars();
    
  4. 像这样更改主主题颜色:

    import {MaterialCssVarsService} from 'angular-material-css-vars';
    
    export class SomeComponentOrService {
      constructor(public materialCssVarsService: MaterialCssVarsService) {
        const hex = '#3f51b5';
        this.materialCssVarsService.changePrimaryColor(hex);
      }
    }
    

答案 2 :(得分:2)

我创建了一个小库 - material-theme-creator

您可以为 angular 应用程序设置主题或使用这种方法来创建主题

NPM:https://www.npmjs.com/package/material-theme-creator

文档:https://artik-man.github.io/material-theme-creator/

npm i material-theme-creator

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

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

第二个主题代码:

.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%);
}

您可以将其与 Angular Material 或 SCSS 或纯 CSS 一起使用

答案 3 :(得分:0)

材料主题创建者呢?

https://www.npmjs.com/package/material-theme-creator

npm i material-theme-creator

  @import '~@angular/material/theming';
  @import "~material-theme-creator/core";

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

  :root {
    @include create-variables-from-map('primary', $mat-teal);
    @include create-variables-from-map('accent', $mat-deep-purple);
    @include 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))); 

答案 4 :(得分:-2)

那么... css变量是运行时的,而不是编译时的。 SASS不知道该怎么办。您应该能够使用SCSS的$ {}插值来重构css var,并使所有内容仍然相同。 http://sass-lang.com/documentation/file.SASS_REFERENCE.html#interpolation_

$primary-color: 196;

:root {
  --primary-color: #{$primary-color};
}

$primary-100: hsl($primary-color, 90%, 98%);