Looking at the Angular Material documentation, they recommend using a -theme
file per component to manage applying any theme-related styles to a specific class.
From my perspective, some downsides to this approach are:
mat-color($primary, 200)
for border colours and now want to change it to mat-color($primary, 300)
. This will have been repeated all throughout the codebase.Given a consistent design language, there will only be a subset of colors that will be used (e.g. 4 colors from the primary palette, 3 from the accent palette, a few different foreground / background colors, etc).
Given the above, doesn't it make more sense to have a _colors.scss
that defines the exact colors using the theme rather than hoping developers extract the correct value from the theme each time?
e.g. maybe something like:
$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
Then rather than creating a separate -theme
file for each component that requires specific colors, I can simply import the colors.scss
file and use the variables directly in the *.component.scss
file.
Just wanting to validate that the above is sound and that I'm not missing anything obvious that's going to cause pain down the track?
The other tricky part is how to actually define these in a separate colors
file efficiently given the file will need access to the theme data.
To read color values from a theme, you can use the get-color-config Sass function. This function returns a Sass map containing the theme's primary, accent, and warn palettes, as well as a flag indicating whether dark mode is set. @use 'sass:map'; @use '@angular/material' as mat; $color-config: mat.
it's very easy to create a custom angular material theme. This will allow you to specify primary, accent and warning colors that will be used on Angular Material components. Your custom theme will be a Sass file and in our case, we'll call it theme. scss and place it in our app's /src folder.
Angular Material's theming system lets you customize color and typography styles for components in your application. The theming system is based on Google's Material Design specification. This document describes the concepts and APIs for customizing colors.
CSS Variables to the Rescue CSS variables is a standard which enables you to have variables in CSS. SCSS is compiled to CSS during compile time, and SCSS variables are replaced with resolved value during compile time, which means there is no way to change the variable during run time.
@mixin
?Just wanting to validate that the above is sound and that I'm not missing anything obvious that's going to cause pain down the track?
The only thing, I can think of, is that you would miss the opportunity to use multiple themes in one application. With the approach from the Angular Material documentation, you would have a @mixin
for each component, that you can @include
multiple times with different $theme
variables.
Example from 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);
}
This wouldn't work, if you import colors as scss-variables into your components and use it there.
The other tricky part is how to actually define these in a separate colors file efficiently given the file will need access to the theme data.
This is actually pretty straight forward: I have a separate file src/styles/_variables.scss
that contains my custom colors as scss-variables and also the $theme
variable, that I am using later in src/theme.scss
.
@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));
To import my _variables.scss
inside a component, I have to add stylePreprocessorOptions
to the angular.json
file:
"styles": [
"src/styles.scss",
"src/theme.scss"
],
"stylePreprocessorOptions": {
"includePaths": [
"src/styles"
]
},
Now I can import my variables in all scss-files of my components:
@import 'variables';
.custom-class-a {
background-color: map-get($custom-colors, custom-color-a);
color: map-get($custom-colors, custom-color-b);
}
map-merge
?As you noticed, I collect my custom colors in the sass-map $custom-colors
and merge them into my $theme
variable. This way I could either use my custom colors by directly importing it into my components style sheet (as described above) or I could use them inside my components @mixin
the way it is described in the Angular Material documentation.
@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);
}
}
Maybe this combination is a way that your frontend devs could work with?
I have defined primary,accent and warn colors as css custom variables in the styles.css file like so:
@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};
}
And used these variables in any of my components like so:( in my-custom-component.scss)
.some-class {
color: var(--primary)
}
.another-class {
background-color: var(--bg)
}
.yet-another-class {
border-color: var(--accent)
}
By doing like this, i can change any value related to color in any component, because these variables are global (defined in styles.css) As i change theme, these colors also change according to new theme's color
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