Можете ли вы применить основной цвет темы Angular к div?

Есть ли способ создать приложение Angular 7, чтобы вы могли:

  • Применяйте темы и к обычным элементам HTML, а не только к компонентам Angular Material.
  • Переключение темы во время выполнения
  • Не нужно использовать класс для каждого цвета и каждого типа использования (color, background-color, border-color, ...), как в некоторых других вопросах и решениях.

Например

Я хочу сделать что-то вроде этого:

<div color="primary">

</div>

Но это не работает, потому что атрибут color предназначен только для угловых компонентов материала.

Кроме того, я хочу иметь возможность изменять цвет фона, цвет текста и т. д. в зависимости от текущей темы. (темная тема, светлая тема)


person MauriceNino    schedule 31.07.2019    source источник


Ответы (2)


О решении

С помощью этого решения вы можете:

  • Переключение темы во время выполнения
  • Получить текущую тему во время выполнения
  • Тема прямо в CSS без использования дополнительных классов или чего-то еще
  • Иметь простое в использовании и понятное решение, которое требует только однократной настройки

Минусы:

  • Использует переменные CSS. Некоторые старые браузеры могут их не поддерживать.
  • Полагается на более новые версии Angular. Я не знаю, будет ли это работать в более старых версиях (проверено в Angular 6 и 7)

Это то, что я использую в своем проекте прямо сейчас:

Настраивать

Сначала нужно определить тему.

Вот пример с именем dark-theme.scss, расположенный в src/themes:

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

// Set variables to whatever colors you want for your app
$dark-theme-primary: mat-palette($mat-pink);
$dark-theme-accent: mat-palette($mat-light-blue);
$dark-theme-warn: mat-palette($mat-red);

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

@include angular-material-theme($dark-theme);

Тогда вам нужна функция SCSS, которая может создавать переменные SCSS и CSS темы:

Вот моя под названием functions.scss в src/assets/scss:

@mixin generate-theme-vars($theme) {
  //default palette foreground/background:
  $foreground-palette: map-get($theme, foreground);
  $background-palette: map-get($theme, background);

  /////////////////////////////////////////////////
  // SCSS VARS
  /////////////////////////////////////////////////

  $primary: mat-color(map-get($theme, primary));
  $accent: mat-color(map-get($theme, accent));
  $warn: mat-color(map-get($theme, warn));

  $base: mat-color($foreground-palette, base);
  $divider: mat-color($foreground-palette, divider);
  $dividers: mat-color($foreground-palette, dividers);
  $disabled: mat-color($foreground-palette, disabled);
  $disabled-button: mat-color($foreground-palette, disabled-button);
  $disabled-text: mat-color($foreground-palette, disabled-text);
  $hint-text: mat-color($foreground-palette, hint-text);
  $secondary-text: mat-color($foreground-palette, secondary-text);
  $icon: mat-color($foreground-palette, icon);
  $icons: mat-color($foreground-palette, icons);
  $text: mat-color($foreground-palette, text);
  $slider-off: mat-color($foreground-palette, slider-off);
  $slider-off-active: mat-color($foreground-palette, slider-off-active);
  
  $status-bar: mat-color($background-palette, status-bar);
  $app-bar: mat-color($background-palette, app-bar);
  $background: mat-color($background-palette, background);
  $hover: mat-color($background-palette, hover);
  $card: mat-color($background-palette, card);
  $dialog: mat-color($background-palette, dialog);
  $disabled-button: mat-color($background-palette, disabled-button);
  $raised-button: mat-color($background-palette, raised-button);
  $focused-button: mat-color($background-palette, focused-button);
  $selected-button: mat-color($background-palette, selected-button);
  $selected-disabled-button: mat-color($background-palette, selected-disabled-button);
  $disabled-button-toggle: mat-color($background-palette, disabled-button-toggle);

  /////////////////////////////////////////////////
  // CSS VARS
  /////////////////////////////////////////////////


  --primary-color: #{$primary};
  --accent-color: #{$accent};
  --warn-color: #{$warn};

  --base-color: #{$base};
  --divider-color: #{$divider};
  --dividers-color: #{$dividers};
  --disabled-color: #{$disabled};
  --disabled-text-color: #{$disabled-text};
  --hint-text-color: #{$hint-text};
  --secondary-text-color: #{$secondary-text};
  --icon-color: #{$icon};
  --icons-color: #{$icons};
  --text-color: #{$text};
  --slider-off-color: #{$slider-off};
  --slider-off-active-color: #{$slider-off-active};

  --status-bar-color: #{$status-bar};
  --app-bar-color: #{$app-bar};
  --background-color: #{$background};
  --hover-color: #{$hover};
  --card-color: #{$card};
  --dialog-color: #{$dialog};
  --disabled-button-color: #{$disabled-button};
  --raised-button-color: #{$raised-button};
  --focused-button-color: #{$focused-button};
  --selected-button-color: #{$selected-button};
  --selected-disabled-button-color: #{$selected-disabled-button};
  --disabled-button-toggle-color: #{$disabled-button-toggle};
}

После этого все готово, и все, что вам нужно сделать, это создать класс для каждой темы в вашем глобальном styles.scss:

@import "functions";
@import "~@angular/material/theming";

// You have to define one of those for every theme you offer
.dark-theme {
    @import "themes/dark-theme";
    @include angular-material-theme($dark-theme);
    @include generate-theme-vars($dark-theme);
}

.light-theme {
    @import "themes/light-theme";
    @include angular-material-theme($light-theme);
    @include generate-theme-vars($light-theme);
}

Применение

Чтобы применить тему, которую вы хотите использовать, вам нужно поместить класс CSS dark-theme (или как вы его назвали) к элементу, который содержит все остальные элементы.

Я поместил его в HTML-тег:

<!doctype html>
<html lang="en" class="dark-theme">
    <!-- ... -->
</html>

Теперь вы можете переключать тему во время выполнения, изменив этот класс с помощью JavaScript, например, на light-theme.

В каждом свойстве CSS, которому нужен цвет, теперь вы можете использовать переменные:

div {
    width: 300px;
    height: 300px;

    background-color: var(--app-bar-color);

    .someText {
        color: var(--text-color);
    }
}

Если вы хотите что-то сделать в своем CSS, если применена специальная тема и изменение заключается не в самом цвете, то сделайте это так:

// Example: We want to remove some div only when the light-theme is used
div {
    width: 300px;
    height: 300px;

    background-color: var(--app-bar-color);

    
    :host-context(.light-theme) & {
        display: none;
    }
}

PS

Для всех, кому может быть интересно, почему я использую @import "functions";, хотя они и находятся в разных папках:

Перейдите в angular.json и добавьте к объекту projects > <YourProject> > architect > build > options следующее:

"stylePreprocessorOptions": {
    "includePaths": [
    "src/assets/scss"
    ]
},

Теперь вы можете использовать @import "functions"; из любого пути.

Если вам нужна поддержка IE (не проверено, может потребоваться работа)

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

div {
    background-color: red; // fallback to red if the variable doesnt exist -> Old browsers, or IE
    background-color: var(--app-bar-color);
}

Зная это, вы могли бы, например, определить несколько переменных SCSS в styles.scss:

@import "functions";
@import "~@angular/material/theming";

// Default theme
@import "themes/dark-theme";
@include angular-material-theme($dark-theme);

// Generate SCSS vars
$foreground-palette: map-get($theme, foreground);
$background-palette: map-get($theme, background);

/////////////////////////////////////////////////
// SCSS VARS
/////////////////////////////////////////////////

$primary: mat-color(map-get($theme, primary));
$accent: mat-color(map-get($theme, accent));
$warn: mat-color(map-get($theme, warn));

// ... and all the other vars from above if you would like


// You have to define one of those for every theme you offer
.dark-theme {
    // Only init the CSS vars here, because the rest is in default
    @include generate-theme-vars($dark-theme);
}

.light-theme {
    @import "themes/light-theme";
    @include angular-material-theme($light-theme);
    @include generate-theme-vars($light-theme);
}

Теперь вы можете использовать его так:

div {
    background-color: $primary; // fallback
    background-color: var(--primary-color);
}

Это больше не может быть изменено динамически с помощью JS во время выполнения!!

person MauriceNino    schedule 31.07.2019
comment
Это выглядит как отличное решение. Однако: я не могу его использовать: @include angular-material-theme($dark-theme);styles.scss, то же самое, что и в вашем ответе). Вы случайно не знаете, почему я получаю это? - person Igor; 28.03.2020
comment
Работает довольно хорошо. Поддержка браузера переменных CSS может быть самым большим недостатком. - person Dschuli; 18.06.2020
comment
@Igor извините, что отвечаю так поздно - я не знаю, почему это не работает. может быть, вы можете отправить мне ошибку? в качестве альтернативы я могу отправить вам репо, где я использовал приведенный выше код. - person MauriceNino; 22.06.2020
comment
@Dschuli Да, согласно caniuse, он поддерживается 95% всех текущих пользователей, но я думаю, это зависит от того, что вы делаете. Некоторые сложные технические вещи -> Я ожидаю, что люди обновят свой браузер. Интернет-журнал для пожилых людей -› да, лучше не использовать его там, я думаю. - person MauriceNino; 22.06.2020
comment
@MauriceNino Думаю, у меня все получилось - так что проблема решена. У меня нет примера CodePen, но я думаю, что это была моя вина, потому что, видимо, теперь ошибка исчезла. Спасибо, хотя - ваш вопрос и ответ действительно помогли! - person Igor; 22.06.2020
comment
@Dschuli Я добавил раздел для поддержки браузеров без переменных CSS, но еще не тестировал его. Может быть идея о том, как бороться с этой проблемой, если это важно. - person MauriceNino; 22.06.2020

Для тех, кто может получить ошибку - SassError: Undefined variable., если вы пытаетесь использовать любую из переменных, определенных в @mixin generate-theme-vars($theme), вам нужно добавить !global в эти переменные. Например, определите: $base: mat-color($foreground-palette, base) !global;

Это сделает переменные глобальными, и вы сможете использовать их где угодно.

person Vaibs007    schedule 28.04.2021
comment
Однако вы должны использовать переменные CSS (а не переменные SASS), или я что-то не так понимаю? - person MauriceNino; 28.04.2021
comment
Я вижу вашу точку зрения. SASS будут изменены в соответствии с темой, которая написана последней в style.scss. Спасибо за вопрос!! - person Vaibs007; 29.04.2021