Angular Material - 全局颜色变量

Posted

技术标签:

【中文标题】Angular Material - 全局颜色变量【英文标题】:Angular Material - Global color variables 【发布时间】:2018-09-13 11:45:08 【问题描述】:

查看 Angular Material 文档,他们建议对每个组件使用 -theme 文件来管理将任何与主题相关的样式应用于特定类。

在我看来,这种方法的一些缺点是:

相当冗长 将样式分成两个不同的位置 所有前端开发人员都需要了解 Angular Material 颜色的工作原理 使更改值变得更加困难(例如,我们可能一直使用 mat-color($primary, 200) 作为边框颜色,现在想将其更改为 mat-color($primary, 300)。这将在整个代码库中重复。

如果设计语言一致,则只会使用一部分颜色(例如,主调色板中的 4 种颜色、重点调色板中的 3 种颜色、几种不同的前景色/背景色等)。

鉴于上述情况,使用_colors.scss 定义使用主题的确切颜色而不是希望开发人员每次都从主题中提取正确的值不是更有意义吗?

例如可能是这样的:

  $clr-primary-default: mat-color($primary);
  $clr-primary-contrast: mat-color($primary, default-contrast);
  $clr-primary-light: mat-color($primary, lighter);
  $clr-primary-dark: mat-color($primary, darker);

  $clr-accent-default: mat-color($accent);
  $clr-accent-light: mat-color($accent, lighter);
  $clr-accent-dark: mat-color($accent, darker);

  $clr-default-text: mat-color($foreground);
  $clr-secondary-text: mat-color($foreground, secondary-text);

  //etc

然后,我可以简单地导入colors.scss 文件并直接在*.component.scss 文件中使用变量,而不是为每个需要特定颜色的组件创建单独的-theme 文件。

只是想验证上述内容是否合理,并且我没有遗漏任何明显会导致痛苦的事情?

另一个棘手的部分是如何在单独的colors 文件中有效地定义这些文件,因为该文件需要访问主题数据。

【问题讨论】:

【参考方案1】:

为什么使用@mixin

只是想验证上述内容是否合理,并且我没有遗漏任何明显会导致痛苦的事情?

我能想到的唯一一件事是,您会错过在一个应用程序中使用多个主题的机会。使用Angular Material documentation 的方法,每个组件都有一个@mixin,您可以使用不同的$theme 变量多次@include

来自https://medium.com/@tomastrajan/the-complete-guide-to-angular-material-themes-4d165a9d24d1的示例:

.default-theme 
  @include angular-material-theme($theme);
  @include custom-component-theme($theme);


.light-theme 
  @include angular-material-theme($light-theme);
  @include custom-component-theme($light-theme);

如果您将颜色作为 scss 变量导入组件并在那里使用它,这将不起作用。

颜色的单独文件

另一个棘手的部分是如何在单独的颜色文件中有效地定义它们,因为文件需要访问主题数据。

这实际上非常简单:我有一个单独的文件 src/styles/_variables.scss,其中包含我的自定义颜色作为 scss-variables 和 $theme 变量,我稍后在 @987654332 中使用@。

@import '~@angular/material/theming';
// Theme configuration
$primary: mat-palette($mat-blue, 800, 500, 900);
$accent:  mat-palette($mat-blue, A200, A100, A400);
$warn: mat-palette($mat-red);

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

// Custom colors
$custom-colors: (
  custom-color-a: mat-color($mat-green, 700),
  custom-color-b: mat-color($mat-red, 400),
);
$theme: map-merge($theme, (custom-colors: $custom-colors));

要在组件中导入我的_variables.scss,我必须add stylePreprocessorOptions to the angular.json file:

"styles": [
  "src/styles.scss",
  "src/theme.scss"
],
"stylePreprocessorOptions": 
  "includePaths": [
    "src/styles"
  ]
,

现在我可以在我的组件的所有 scss 文件中导入我的变量:

@import 'variables';

.custom-class-a 
  background-color: map-get($custom-colors, custom-color-a);
  color: map-get($custom-colors, custom-color-b);

为什么我使用sass-map 和map-merge

如您所见,我在 sass-map $custom-colors 中收集自定义颜色并将它们合并到我的 $theme 变量中。这样,我可以通过直接将自定义颜色导入到我的组件样式表中来使用我的自定义颜色(如上所述)或者我可以在我的组件@mixin 中使用它们,就像 Angular Material 中描述的那样文档。

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

@mixin custom-component-theme($theme) 
  $custom-colors: map-get($theme, custom-colors);

  .custom-class-a 
    background-color: map-get($custom-colors, custom-color-a);
    color: map-get($custom-colors, custom-color-b);
  

也许这种组合是您的前端开发人员可以使用的一种方式?

【讨论】:

实际问题是: 1) 我们需要一个单独的全局颜色变量文件,其中包含所有的 $color-variables。 2) 当应用程序主题改变时,将 $theme 对象传递给全局颜色变量文件并从主题中填充那些 $color-variable,3) 现在在任何组件中导入颜色文件,4) 使用颜色变量来设置您的样式html 元素。 我喜欢它。不错。【参考方案2】:

我在 styles.css 文件中将主要颜色、强调颜色和警告颜色定义为 css 自定义变量,如下所示:

@import "~@angular/material/theming";
@include mat-core();

$my-primary: mat-palette($mat-blue-grey);
$my-accent: mat-palette($mat-amber, A200, A100, A400);
$my-warn: mat-palette($mat-deep-orange);

$my-2-primary: mat-palette($mat-pink, 400, 200, 600);
$my-2-accent: mat-palette($mat-blue, A200, A100, A400);
$my-2-warn: mat-palette($mat-deep-orange, 500, 300, 700);

.dark-theme 
  $my-theme-dark: mat-dark-theme($my-primary, $my-accent, $my-warn);
  @include angular-material-theme($my-theme-dark);
  $primary: mat-color($my-primary);
  $accent: mat-color($my-accent);
  $warn: mat-color($my-warn);
  $fg_palette:map-get($my-theme-dark, foreground);
  $bg_palette:map-get($my-theme-dark, background);
  $fg:map-get($fg_palette, text);
  $bg:map-get($bg_palette, background);

  --primary: #$primary;
  --accent: #$accent;
  --warn: #$warn;
  --fg: #$fg;
  --bg: #$bg;


.dark-theme-2 
  $my-2-theme-dark: mat-dark-theme($my-2-primary, $my-2-accent, $my-2-warn);
  @include angular-material-theme($my-2-theme-dark);
  $primary: mat-color($my-2-primary);
  $accent: mat-color($my-2-accent);
  $warn: mat-color($my-2-warn);
  $fg_palette:map-get($my-2-theme-dark, foreground);
  $bg_palette:map-get($my-2-theme-dark, background);
  $fg:map-get($fg_palette, text);
  $bg:map-get($bg_palette, background);

  --primary: #$primary;
  --accent: #$accent;
  --warn: #$warn;
  --fg: #$fg;
  --bg: #$bg;

并在我的任何组件中使用这些变量,如下所示:(在 my-custom-component.scss 中)

.some-class 
    color: var(--primary)


.another-class 
    background-color: var(--bg)


.yet-another-class 
    border-color: var(--accent)

通过这样做,我可以更改任何组件中与颜色相关的任何值,因为这些变量是全局的(在 styles.css 中定义) 当我更改主题时,这些颜色也会根据新主题的颜色而变化

【讨论】:

请注意,这不适用于 IE 和许多旧版本的浏览器,因为它依赖于较新的 CSS。 能否提供动态更改主题的代码? 谢谢,这正是我要找的答案。 @kushalBaldev - 这会因为 var(--varname) 而不起作用吗?【参考方案3】:

我正在做一个使用 Material 2 主题的项目,我使用了这种方法,我使用类名并全局添加颜色类。

这就是我所做的:

文件名:mytheme-sidemenu.scss:

// Import all the tools needed to customize the theme and extract parts of it
@import "~@angular/material/theming";
// Define a mixin that accepts a theme and outputs the color styles for the component.
@mixin mytheme-sidemenu($theme) 
  // Extract whichever individual palettes you need from the theme.
  $primary: map-get($theme, primary);
  $accent: map-get(
    $theme,
    accent
  ); // Use mat-color to extract individual colors from a palette as necessary.

  .col-primary 
    color: mat-color($primary, 500) !important;
  
  .col-accent 
    color: mat-color($accent, 300) !important;
  

这是我的主要主题文件: mytheme-theme.scss:

@import '~@angular/material/theming';
@import './variables/helper.scss';
@import './variables/spacemanager.scss';
@import './mytheme-sidemenu.scss';

// Primary theme
@include mat-core();
$mytheme-app-primary: mat-palette($mat-light-blue, 700, 600);
$mytheme-app-accent: mat-palette($mat-pink, A200, 900, A100);
$mytheme-app-warn: mat-palette($mat-deep-orange);
$mytheme-app-theme: mat-light-theme($mytheme-app-primary, $mytheme-app-accent, $mytheme-app-warn);
@include angular-material-theme($mytheme-app-theme);
// Secondary Theme
.mytheme-alt-theme 
    $mytheme-alt-primary: mat-palette($mat-blue-grey, 500);
    $mytheme-alt-accent: mat-palette($mat-pink, 500);
    $mytheme-alt-warn: mat-palette($mat-deep-orange);
    $mytheme-alt-theme: mat-light-theme($mytheme-alt-primary, $mytheme-alt-accent, $mytheme-alt-warn);
    @include angular-material-theme($mytheme-alt-theme);

// Using the $theme variable from the pre-built theme you can call the theming function
@include mytheme-sidemenu($mytheme-app-theme);

并在 app.module.ts 中更新:

export class AppModule 
  constructor(
    @Inject(OverlayContainer) private overlayContainer: OverlayContainer
  ) 
    this.overlayContainer
      .getContainerElement()
      .classList.add("mytheme-alt-theme"); // this for double theme add to the root css class
  

【讨论】:

以上是关于Angular Material - 全局颜色变量的主要内容,如果未能解决你的问题,请参考以下文章

如何有效地使用 Angular Material 自定义调色板颜色 Angular Material

Angular 2 Material - 如何有条件地设置工具栏的颜色

Angular Material Table - 将动态背景颜色应用于一行(Angular 2+)

Angular Material(组件)中的条件按钮颜色属性

Angular Material mat-spinner 自定义颜色

如何更改 Angular Material2 中主调色板的字体颜色?