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

Posted

技术标签:

【中文标题】使用 CSS 变量创建角度材质主题【英文标题】:Create angular material theme with CSS variables 【发布时间】:2019-07-02 21:22:04 【问题描述】:

我正在开发一个需要在运行时进行主题化的项目。所以我创建了一个将 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 变量创建自定义材质主题?

【问题讨论】:

我刚刚使用 hsl() scss 函数测试了我的项目,它工作正常。您的 angular.json 中是否有 "stylePreprocessorOptions": "includePaths": [ "src","src/assets/scss" ] 属性,以便您的 var.scss 可以在全球范围内获取? 您确定您使用的mat-palette 正确吗?我找不到将数组传递给它的示例 @Budhead2004 我的 var.scss 包含得非常好。我到处都在使用它。 @Budhead2004 您是否将 CSS 变量传递给 hsl 函数? 你能告诉我你传递给 hsl() 函数的 $var 的内容吗? @Dirk 他正确使用了 mat-palette 功能,这正是我的自定义主题的设置方式。 【参考方案1】:

Sooo... css 变量是运行时,而不是编译时。 SASS 不知道如何处理它们。您应该能够使用 SCSS 的 $ 插值重构您的 css 变量,并让一切仍然正常工作。 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%);

【讨论】:

我不需要 SCSS 知道如何处理它,SCSS 只会将它放在指定的值上,浏览器会解释它。其次,我想要这个的原因是我应该能够在运行时更改主题。【参考方案2】:

如果您升级到 @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, ',') 更改为在字符串中找到最后一个 ',' 的内容。不幸的是,我的 sass 知识只涵盖了最低限度,我不知道该怎么做:/

【讨论】:

哇!听起来不错,我没有时间检查,但这似乎是合法的! @function colorToVariable($hexColor) @return "#red($hexColor),#green($hexColor),#blue($hexColor)"; 和后来的--color-primary-lighter: #colorToVariable(#ff0000); 一起工作得很好,以避免手动rgb 转换【参考方案3】:

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

你可以这样使用它:

    安装:

    npm i angular-material-css-vars -S
    

    然后从主样式表文件中删除所有现有的@import '~@angular/material/theming';

    将此添加到您的主样式表中:

    @import '~angular-material-css-vars/main';
    @include initMaterialCssVars();
    

    像这样改变主主题颜色:

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

【讨论】:

您好,我们可以在您提到的库中应用字体样式吗?【参考方案4】:

我创建了一个小库 - 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 一起使用

【讨论】:

以上是关于使用 CSS 变量创建角度材质主题的主要内容,如果未能解决你的问题,请参考以下文章

创建自定义角度材质主题时最好的方法是啥?

如何更改特定角度材质选项卡的背景颜色?

如何在 TypeScript / JavaScript 中使用角度材质主题颜色?

如何使用 angular5 和 angular 材质创建自定义颜色主题

如何在角度材质中定义自定义主题以控制按钮文本的颜色?

Angular 材质 io 预定义主题颜色