Получить материал 2 цветовой схемы темы/палитры для других элементов

Я создаю приложение, но хочу сохранить согласованную цветовую схему, которую можно изменить с помощью настроек, поэтому я использую Material (2) с угловым (2+), но я не уверен, как получить цветовую схему для элементов, которые не прямо предложите возможность окрасить их с color="primary" так что мне остается попытаться выяснить, как получить цвет/цветовую схему, которую использует моя тема Material 2. И я хочу, чтобы он менялся при изменении темы, например, моя панель навигации будет адаптироваться к изменению темы, потому что она установлена на

<mat-toolbar color="primary" class="fixed-navbar mat-elevation-z10">

Но элемент сетки из Материала 2 не принимает тот же аргумент, поэтому у меня остается попытка стилизовать его в достаточно близком цвете или просто не соответствовать ему вообще (и он не будет приспосабливаться к изменениям темы), как показано здесь:

enter image description here

Я хочу, чтобы он совпадал по цвету с матом темы, который находится здесь (и изменяется при выборе параметров в настройках панели навигации)

@import '[email protected]/material/theming';

@include mat-core();



$candy-app-primary: mat-palette($mat-red);
$candy-app-accent:  mat-palette($mat-deep-orange, A200, A100, A400);
$candy-app-warn:    mat-palette($mat-red);
$candy-app-theme: mat-dark-theme($candy-app-primary, $candy-app-accent, $candy-app-warn);

// Include theme styles for core and each component used in your app.
// Alternatively, you can import and @include the theme mixins for each component
// that you are using.
.default {
  @include angular-material-theme($candy-app-theme);
}
.light {
  $light-primary: mat-palette($mat-blue, 200,300, 900);
  $light-accent:  mat-palette($mat-light-blue, 600, 100, 800);
  $light-warn:    mat-palette($mat-red, 600);
  $light-theme: mat-dark-theme($light-primary, $light-accent, $light-warn);
  @include angular-material-theme($light-theme);
}
@include angular-material-theme($candy-app-theme);

Ответ 1

Я нашел отличный обходной путь !!!! Я так взволнован, чтобы показать это, потому что это мешало мне, как реализовать это целую вечность Так что здесь идет; Во-первых, измените все ваши CSS файлы на Scss;

Для существующих проектов

  • Запустите в консоли ng set defaults.styleExt=scss

  • Переименуйте все существующие .css файлы в .scss

  • Вручную измените расширение файла styles в .angular-cli.json с .css на .scss
  • Если вы не использовали такой инструмент, как WebStorm Refactor, для переименования, то вручную измените все styleUrls с .css на .scss

Для будущих проектов

  • Просто для вашего нового проекта просто используйте ng new your-project-name --style=scss

  • Для всех новых проектов использовать scss используйте ng set defaults.styleExt=scss --global

Теперь вам нужно будет иметь файл theme.scss в корне вашего приложения, например: where themes are

Теперь в вашем файле style.scss вы хотите добавить следующее (как вы можете видеть, я ссылаюсь на background-color, но вы можете изменить его на любой элемент в теме вашего сайта, как вы хотите):

РЕДАКТИРОВАТЬ: Вам НЕ НУЖНО помещать этот пользовательский элемент @mixin в ваш styles.scss вы можете поместить его в любое из ваших *name*.component.scss а затем просто импортировать и включить его так же, как вы делали с приведенным примером!

@import '[email protected]/material/theming';

// Define a custom mixin that takes in the current theme
@mixin theme-color-grabber($theme) {
  // Parse the theme and create variables for each color in the pallete
  $primary: map-get($theme, primary);
  $accent: map-get($theme, accent);
  $warn: map-get($theme, warn);
  // Create theme specfic styles
  .primaryColorBG {
    background-color: mat-color($primary);
  }
  .accentColorBG {
    background-color: mat-color($accent);
  }
  .warnColorBG {
    background-color: mat-color($warn);
  }
}

Теперь перейдите к файлу theme.scss, который вы используете для тематики ваших материалов 2, если вам нужна помощь, проверьте это: Material 2 Github - Руководство по созданию тем

Теперь откройте ваш theme.scss и импортируйте свой style.scss, так как мой theme.scss находится в корне папки /src/app/theme.scss я должен сначала выйти из нее, чтобы сослаться на мой глобальный /src/styles.scss стилизовать файл так;

@import '../styles';

Затем мы должны включить наш новый пользовательский @mixin мы создали во ВСЕ наши темы (если у вас есть несколько таких же, как у меня, поэтому он меняет цвет в соответствии с текущей выбранной темой).

Включите его выше фактической темы angular-material-theme, например так:

@include theme-color-grabber($theme);
@include angular-material-theme($theme);

Если у вас есть такие темы, как я, добавьте их в ту же позицию, например:

.light {
  $light-primary: mat-palette($mat-blue, 200,300, 900);
  $light-accent:  mat-palette($mat-light-blue, 600, 100, 800);
  $light-warn:    mat-palette($mat-red, 600);
  $light-theme: mat-dark-theme($light-primary, $light-accent, $light-warn);
  @include theme-color-grabber($light-theme);
  @include angular-material-theme($light-theme);

}

Вы можете видеть, что я добавил свой theme-color-grabber над включением, это не имеет значения, находится ли он выше или ниже фактической темы, потому что он получает цвета тем, что является основным пунктом.

Вся моя themes.scss выглядит так:

@import '[email protected]/material/theming';
//We import our custom scss component here
@import '../styles';

@include mat-core();

$theme-primary: mat-palette($mat-red);
$theme-accent:  mat-palette($mat-deep-orange, A200, A100, A400);
$theme-warn:    mat-palette($mat-red);
$theme: mat-dark-theme($theme-primary, $theme-accent, $theme-warn);
//
@include theme-color-grabber($theme);
@include angular-material-theme($theme);
.light {
  $light-primary: mat-palette($mat-blue, 200,300, 900);
  $light-accent:  mat-palette($mat-light-blue, 600, 100, 800);
  $light-warn:    mat-palette($mat-red, 600);
  $light-theme: mat-dark-theme($light-primary, $light-accent, $light-warn);
  @include theme-color-grabber($light-theme);
  @include angular-material-theme($light-theme);

}

И, наконец, теперь мы можем вызывать цвет наших тем для фона ВСЕГДА !, например, я даю mat-grid-tile "основной" цвет (он не принимает аргумент color = '', как и другие элементы, такие как мат -toolbar), просто установив для его класса соответствующее имя класса, например:

РЕДАКТИРОВАТЬ: В каждом из ваших scss файлов компонентов вам нужно будет import '<path-to>/theme.scss' чтобы ваша тема применялась к этому компоненту. Не импортируйте theme.scss в styles.scss потому что это создаст цикл импорта!

<mat-grid-list cols="4" rows="4" rowHeight="100px">
  <mat-grid-tile
    colspan="4"
    rowspan="5"
  class="primaryColorBG">
    <div fxLayout="column" fxLayoutAlign="center center">
      <h1 class="title-font">Callum</h1>
      <h1 class="title-font">Tech</h1>
    </div>
    <p>
      Ambitious and ready to take on the world of Information Technology,<br>
      my love for programming and all things I.T. has not wavered since I first got access<br>
      to my fathers computer at age 9.
    </p>
  </mat-grid-tile>

</mat-grid-list>

Наконец-то наш результат будет выглядеть так!

Красная тема активна Red theme

Синяя тема активна enter image description here

Ответ 2

Я лично помещаю их в переменные css4, чтобы использовать их без импорта, например

background: var(--color-primary)

А вот как настроить переменные css4

@import '[email protected]/material/theming';
// Include the common styles for Angular Material. We include this here so that you only
// have to load a single css file for Angular Material in your app.
// Be sure that you only ever include this mixin once!
@include mat-core();

// Define the palettes for your theme using the Material Design palettes available in palette.scss
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
// hue. Available color palettes: https://material.io/design/color/
$app-primary: mat-palette($mat-blue);
$app-accent:  mat-palette($mat-orange);
$app-warn:    mat-palette($mat-red);
$app-success: mat-palette($mat-light-green);

// Create the theme object (a Sass map containing all of the palettes).
$app-theme: mat-light-theme($app-primary, $app-accent, $app-warn);

// Include theme styles for core and each component used in your app.
// Alternatively, you can import and @include the theme mixins for each component
// that you are using.
@include angular-material-theme($app-theme);

$primary: map-get($app-theme, primary);
$accent: map-get($app-theme, accent);

:root {
  --color-primary: #{mat-color($app-primary)};
  --color-accent: #{mat-color($app-accent)};
  --color-warn: #{mat-color($app-warn)};
  --color-success: #{mat-color($app-success)};
}

теперь цвета могут использоваться в файлах CSS без импорта с

background: var(--color-primary)

Ответ 3

UPDATE:

Новая версия этого решения была опубликована здесь:

https://github.com/mirismaili/angular-material-dynamic-themes

If you only need the answer of the asked question, probably is better to refer to the first version of the answer, below. Also, I recommend to read this section of the above repo documentation: Use material themes for other elements.

But if want other capabilities you see in the below video, I recommend this new approach.

Video

Thank StackBlitz


АРХИВ ОТВЕТА:

enter image description here

стекблиц здесь


Самые важные части:

В вашем styles.scss (или themes.scss, если есть):

@import '[email protected]/material/theming';

@include mat-core();

@mixin define-css-classes($theme) {
    @include angular-material-theme($theme);

    $primary: map-get($theme, primary);
    $accent: map-get($theme, accent);
    $warn: map-get($theme, warn);
    $background: map-get($theme, background);
    $foreground: map-get($theme, foreground);

    // CSS THEME-DEPENDENT-STYLES ARE HERE:
    .theme-dependent-colors {
        background: mat-color($primary);
        color: mat-color($accent);
    }
}

/**
* Define your custom themes in this map. 
* The 'key' of each member is the name of CSS class for that theme. 
* To better understand the schema of the map, see '@each' loop below and especially pay attention to 'map-has-key()' functions.
*/ 
$app-themes: (
        indigo-pink : (primary-base: $mat-indigo, accent-base: $mat-pink),
        deeppurple-amber: (primary-base: $mat-deep-purple, accent-base: $mat-amber),
        pink-bluegrey : (primary-base: $mat-pink, accent-base: $mat-blue-gray, is-dark: true),
        purple-green : (primary-base: $mat-purple, accent-base: $mat-green, is-dark: true),
);

@each $css-class, $theme in $app-themes {
    $primary: if(map-has-key($theme, primary), map-get($theme, primary), mat-palette(map-get($theme, primary-base)));

    $accent: if(map-has-key($theme, accent), map-get($theme, accent), mat-palette(map-get($theme, accent-base)));

    $warn: if(map-has-key($theme, warn), map-get($theme, warn), mat-palette(
            if(map-has-key($theme, warn-base), map-get($theme, warn-base), $mat-red)
    ));

    .#{$css-class} {
        @include define-css-classes(mat-light-theme($primary, $accent, $warn));
    }

    .#{$css-class}-dark {
        @include define-css-classes(mat-dark-theme($primary, $accent, $warn));
    }

    .theme-primary.#{$css-class} {
        background-color: mat-color($primary);
    }

    ...
}

Динамическое изменение темы с использованием setTheme() в машинописном тексте (см. здесь и здесь):

import {Component, HostBinding} from '@angular/core';
import {OverlayContainer} from "@angular/cdk/overlay";

const THEME_DARKNESS_SUFFIX = '-dark';

export class AppComponent {
    @HostBinding('class') activeThemeCssClass: string;
    isThemeDark = false;
    activeTheme: string;

    setTheme(theme: string, darkness: boolean = null) {
        if (darkness === null)
            darkness = this.isThemeDark;
        else if (this.isThemeDark === darkness) {
            if (this.activeTheme === theme) return;
        } else
            this.isThemeDark = darkness;

        this.activeTheme = theme;

        const cssClass = darkness === true ? theme + THEME_DARKNESS_SUFFIX : theme;

        const classList = this.overlayContainer.getContainerElement().classList;
        if (classList.contains(this.activeThemeCssClass))
            classList.replace(this.activeThemeCssClass, cssClass);
        else
            classList.add(cssClass);

        this.activeThemeCssClass = cssClass;
    }

    constructor(overlayContainer: OverlayContainer) {
        this.setThemeClass('indigo-pink', false); // Default theme
    }
}

Смотрите другие вещи в стеклец.


CAVEAT: добавление в приложение 8 динамических тем материала (4 источника света + 4 темноты) увеличило размер встроенного styles.css на ~420 kB в моем случае (по сравнению с одной темой статического материала).

Ответ 4

Я абсолютный новичок, и, возможно, это из-за передовой практики, бесполезной для этого случая или решения, требующего много ресурсов, но в myangularthemefile.scss я создал следующие классы:

@import '[email protected]/material/theming';
@include mat-core();

...

.matcolorprimary{
    color: mat-color($mitjans-primary)
}

.matcoloraccent {
    color: mat-color($mitjans-accent);
}

.matcolorwarn {
    color: mat-color($mitjans-warn);
}

И я добавляю их в те HTML-элементы, которые мне нужны в шаблоне компонента.

Я полагаю, было бы легко создать такую же структуру для фоновых цветов...

Может ли это быть альтернативой включению sass-артефактов в каждую таблицу стилей компонента shadow dom для небольших проектов?

Ответ 5

  1. Установите правило стилей приложения на SASS:
    Обновление темы пользовательских компонентов во время выполнения требует использования @mixin поэтому правила стиля вашего приложения должны быть SASS (не CSS). Вы можете прочитать здесь о том, как настроить Angular-Cli с SASS: https://scotch.io/tutorials/using-sass-with-the-angular-cli

  2. Определите @mixin для пользовательского компонента:
    В каждом компоненте, который использует цвета темы, создайте @mixin в своем файле.scss. Для этого компонента извлеките все определения цвета. И переместите их в @mixin, вот так:

// --- file: my-component_1.scss ---
@import '[email protected]/material/theming'; // we need to add this so we could use Material functions
@mixin set-theme-component-1($theme)
{
  // Extract whichever individual palettes you need from the theme.
  $primary-palette: map-get($theme, primary);
  $accent-palette:  map-get($theme, accent);
  $warn-palette:    map-get($theme, warn);

  .component-container
  {
    background-color: mat-color($primary-palette); // use the mat-color function to extract the color from the palette
    border-color: mat-color($warn-palette);
  }
}

// Style rules that aren't theme/color related (size, font, etc)
.component-container
{
  width: 100%;
  ...
}
  1. Определите файл темы:
    Вам нужно будет определить файл темы (если вы этого еще не сделали) и вызвать @mixin мы определили в этом файле, например:
// --- file: app.theme.scss ---
@import '[email protected]/material/theming';
@include mat-core(); // include this only once in your code!!!

// each custom component that uses theme colors will be imported here - we need there @mixin
@import './some-path/some-folder/my-component_1'; // no need to specify .scss suffix

@mixin set-theme($theme) // define a new @mixin that will be invoked each time the theme is changed
{
  @include set-theme-component-1($theme); // invoke the mixin we defined for component_1
  // repeat this for each component that uses theme colors
}

// define your themes:
.theme-light
{
  $light-primary: mat-palette($mat-indigo);
  $light-accent:  mat-palette($mat-pink, A200, A100, A400);
  $light-warn:    mat-palette($mat-red);
  $light-theme:   mat-light-theme($light-primary, $light-accent, $light-warn);

  @include angular-material-theme($light-theme);
  @include set-theme($light-theme); // once the theme was set, invoke the mixin
}

.theme-dark
{
  $dark-primary:  mat-palette($mat-teal, A400);
  $dark-accent:   mat-palette($mat-grey, 800);
  $dark-warn:     mat-palette($mat-red, 700);
  $dark-theme:    mat-dark-theme($dark-primary, $dark-accent, $dark-warn);

  @include angular-material-theme($dark-theme);
  @include set-theme($dark-theme); // once the theme was set, invoke the mixin
}

Что то :-)

Это несколько дополнительных шагов, которые вам нужно выполнить для того, чтобы они работали в реальном времени (они не связаны с пользовательскими компонентами, поэтому я только быстро их брошу).
- Создайте ThemeService, который сохранит текущую тему. Этой службе потребуется обновить OverlayContainer (материал Angular использует этот контейнер для фона модальных объектов, таких как всплывающие окна и выпадающие списки).
- Добавьте класс темы (theme-dark или любой другой) к одному из корневых элементов в DOM.
- Добавьте класс mat-app-background к одному из корневых элементов в DOM. Это изменит цвет фона и цвет шрифта в соответствии с темой.
- Для лучшего проектирования программного обеспечения - если у вас много тем, разделение файла темы может быть хорошей идеей для техобслуживания.

Вы можете продолжить чтение здесь: https://material.angular.io/guide/theming

или посмотрите там проект Github: https://github.com/angular/material2/blob/master/src/lib/core/theming/_theming.scss