Is there a way to theme an Angular 7 application, so that you can:
color
, background-color
, border-color
, ...), like in some other questions and solutions.I want to do something like this:
<div color="primary">
</div>
But that does not work, because the color
attribute is only for angular material components.
Also, I want to be able to change the background color, text color, and so on, depending on the current theme. (Dark theme, Light theme)
With this solution you can:
Cons:
This is what I am using in my project right now:
First you need to define a theme.
Here is an example called dark-theme.scss
located in 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);
Then you need a SCSS function that can create theme SCSS and CSS variables:
Here is mine called functions.scss
in 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};
}
After that, you are all set and all you have to do is to create a class for every theme in your global 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);
}
To apply the theme you want to use, you need to put the CSS class dark-theme
(or whatever you called it) to an element that contains all other elements.
I put it to the HTML tag:
<!doctype html>
<html lang="en" class="dark-theme">
<!-- ... -->
</html>
Now you can switch the theme on runtime, by changing that class with JavaScript to light-theme
for example.
In every CSS property that wants a color, you can use variables now:
div {
width: 300px;
height: 300px;
background-color: var(--app-bar-color);
.someText {
color: var(--text-color);
}
}
If you want to do something in your CSS if a special theme is applied and the change is not the color itself, then do it like this:
// 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;
}
}
For everyone who might wonder why I am using @import "functions";
, even though they are in different folders:
Go into angular.json
and add to the object projects > <YourProject> > architect > build > options
the following:
"stylePreprocessorOptions": {
"includePaths": [
"src/assets/scss"
]
},
Now you can use @import "functions";
from every path.
So if you can't use CSS variables on some clients, you can define a fallback for the specified colors like so:
div {
background-color: red; // fallback to red if the variable doesnt exist -> Old browsers, or IE
background-color: var(--app-bar-color);
}
With this knowledge, you could for example define a few SCSS variables in 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);
}
Now you could use it like this:
div {
background-color: $primary; // fallback
background-color: var(--primary-color);
}
This cant be changed dynamically with JS during the runtime anymore though!!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With