Получить материал 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;
Для существующих проектов
Для будущих проектов
Теперь вам нужно будет иметь файл 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.
![Demo application video 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
-
Установите правило стилей приложения на SASS:
Обновление темы пользовательских компонентов во время выполнения требует использования @mixin
поэтому правила стиля вашего приложения должны быть SASS (не CSS). Вы можете прочитать здесь о том, как настроить Angular-Cli с SASS: https://scotch.io/tutorials/using-sass-with-the-angular-cli
-
Определите @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%;
...
}
- Определите файл темы:
Вам нужно будет определить файл темы (если вы этого еще не сделали) и вызвать @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