How to Use a Material Theme Colors in My CSS in Angular2

How do I use a material theme colors in my css in Angular2?

You have to first import the theme with

@import '~@angular/material/prebuilt-themes/deeppurple-amber.css';

Then you have to define a mixin like

@mixin primary-color($theme) {

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

//Then you can use `mat-color` to get the `primary` color
.a-class {
background-color: mat-color($primary);
}
}

Reference Link: Documentation

Get Angular Material theme color scheme/palette for other elements

I found an awesome workaround!!!!
I'm so excited to show this because its been bugging me how to implement this for ages.
So here goes;
First, change all of your css files to scss;

For existing projects

  • Run in console ng set defaults.styleExt=scss

(ng set seems to have been depreciated, but you can check out this for a fix thanks to user @wlyles get/set have been deprecated in favor of the config command )

  • Rename all existing .css files to .scss
  • Manually change the file extention of styles in .angular-cli.json from .css to .scss
  • If you didnt use a tool like WebStorm Refactor to rename then manually change all the styleUrls from .css to .scss

For future projects

  • Just for your new project simply use ng new your-project-name --style=scss

  • For all new projects to use scss use ng set defaults.styleExt=scss --global

Now you will need to have a theme.scss file in your app root like so:
where themes are

Now in your style.scss file you want to add the following (as you can see I referrence background-color but you can change this to any element to theme your site however you want):

EDIT: You dont NEED to put this custom @mixin element in your styles.scss you can put it in any one of your *name*.component.scss and then simply import and include it the same way you do with the example given!

@import '~@angular/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);
}
}

Now go to your theme.scss file that you use to theme your Material 2 items, if you need help theming check this out: Material 2 Github - Theming guide

Now open your theme.scss and import your style.scss, since my theme.scss is within the root of the /src/app/theme.scss folder I must first go out of it to reference my /src/styles.scss global styling file like so;

@import '../styles';

Then we must actually include our new custom @mixin we created in ALL our themes (if you have multiple like I do, so it changes color according to current selected theme).

Include it above the actual angular-material-theme include, like so:

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

If you have any themes like me add it in the same position like so:

.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);

}

You can see I added my theme-color-grabber above the include, it doesnt really matter if its above or below the actual theme because its getting the themes colors which is the main point.

My whole themes.scss looks like this:

@import '~@angular/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);

}

And finally we can now call on our themes color for a background ANYWHERE!, for instance I give a mat-grid-tile the 'primary' color (it doesn't take the color='' argument, like other elements such as mat-toolbar) by simply setting its class to the appropriate class name like so:

EDIT: In each of your components scss files, you will need to import '<path-to>/theme.scss' in order for your theme to apply to that component. Don't import theme.scss in styles.scss because that will create an import loop!

<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>

Finally our result will look like this!:

Red theme active
Red theme

Blue theme active
Sample Image

How to understand what colors are being used in angular material theme for the components?

At the end of this answer I show the source code to find exactly which hues are used from the palette, but you really don't need to worry about it.

You can choose which of the three themes to use with the color property of the component, and that's really the only decision you're supposed to make. The component designers will choose exactly which hue is appropriate for which piece of the component. The reason they want you to design an entire theme to override colours is so that all pieces of a component have the same relative hues, they don't want you overriding only one piece of a component.

The guide that you linked (https://material.angular.io/guide/theming) describes how to override the theme for an entire project or a single component, and within a specific scope:

You can use Angular Material's Sass mixins to customize component
styles within a specific scope in your application. The CSS rule
declaration in which you include a Sass mixin determines its scope.
The example below shows how to customize the color of all buttons
inside elements marked with the .my-special-section CSS class.

@use '@angular/material' as mat;
.my-special-section { $special-primary:
mat.define-palette(mat.$orange-palette); $special-accent:
mat.define-palette(mat.$brown-palette); $special-theme:
mat.define-dark-theme(( color: (primary: $special-primary, accent:
$special-accent), ));

@include mat.button-color($special-theme); }

I did a bit of digging through the source code and found the function that defines palettes here: https://github.com/angular/components/blob/master/src/material/core/theming/_theming.scss

You can see the default value is 500, lighter is 100, and darker is 700

/// Creates a map of hues to colors for a theme. This is used to define a theme palette in terms
/// of the Material Design hues.
/// @param {Map} $base-palette Map of hue keys to color values for the basis for this palette.
/// @param {String | Number} $default Default hue for this palette.
/// @param {String | Number} $lighter "lighter" hue for this palette.
/// @param {String | Number} $darker "darker" hue for this palette.
/// @param {String | Number} $text "text" hue for this palette.
/// @returns {Map} A complete Angular Material theming palette.

@function define-palette($base-palette, $default: 500, $lighter: 100, $darker: 700,
$text: $default) {
$result: map.merge($base-palette, (
default: _get-color-from-palette($base-palette, $default),
lighter: _get-color-from-palette($base-palette, $lighter),
darker: _get-color-from-palette($base-palette, $darker),
text: _get-color-from-palette($base-palette, $text),

default-contrast: get-contrast-color-from-palette($base-palette, $default),
lighter-contrast: get-contrast-color-from-palette($base-palette, $lighter),
darker-contrast: get-contrast-color-from-palette($base-palette, $darker)
));

// For each hue in the palette, add a "-contrast" color to the map.
@each $hue, $color in $base-palette {
$result: map.merge($result, (
'#{$hue}-contrast': get-contrast-color-from-palette($base-palette, $hue)
));
}

@return $result;
}

They will generally import a color into the component using this function:

/// Gets a color from a theme palette (the output of mat-palette).
/// The hue can be one of the standard values (500, A400, etc.), one of the three preconfigured
/// hues (default, lighter, darker), or any of the aforementioned prefixed with "-contrast".
///
/// @param {Map} $palette The palette from which to extract a color.
/// @param {String | Number} $hue The hue from the palette to use. If this is a value between 0
// and 1, it will be treated as opacity.
/// @param {Number} $opacity The alpha channel value for the color.
/// @returns {Color} The color for the given palette, hue, and opacity.

@function get-color-from-palette($palette, $hue: default, $opacity: null) {
// If hueKey is a number between zero and one, then it actually contains an
// opacity value, so recall this function with the default hue and that given opacity.
@if meta.type-of($hue) == number and $hue >= 0 and $hue <= 1 {
@return get-color-from-palette($palette, default, $hue);
}

// We cast the $hue to a string, because some hues starting with a number, like `700-contrast`,
// might be inferred as numbers by Sass. Casting them to string fixes the map lookup.
$color: if(map.has-key($palette, $hue), map.get($palette, $hue), map.get($palette, $hue + ''));

@if (meta.type-of($color) != color) {
// If the $color resolved to something different from a color (e.g. a CSS variable),
// we can't apply the opacity anyway so we return the value as is, otherwise Sass can
// throw an error or output something invalid.
@return $color;
}

@return rgba($color, if($opacity == null, opacity($color), $opacity));
}

For example the highlighted tab color is imported here: https://github.com/angular/components/blob/master/src/material/tabs/_tabs-theme.scss

.mat-tab-group, .mat-tab-nav-bar {
$theme-colors: (
primary: $primary,
accent: $accent,
warn: $warn
);

@each $name, $color in $theme-colors {
// Set the foreground color of the tabs
&.mat-#{$name} {
@include _label-focus-color($color);
@include _ink-bar-color($color);

// Override ink bar when background color is the same
&.mat-background-#{$name} {
> .mat-tab-header, > .mat-tab-link-container {
@include _ink-bar-color($color, default-contrast);
}
}
}
}

@mixin _ink-bar-color($color, $hue: default) {
.mat-ink-bar {
background-color: theming.get-color-from-palette($color, $hue);
}
}

So the ink bar will be the default (500) color of the theme (primary, accent, or warn).

Why My custom colors are not working in my Angular material theme?

I think only one step was missing: Adding .mat-success and .mat-danger CSS classes:

.mat-success {
background-color: material.get-color-from-palette($custom-success, 500);
color: material.get-color-from-palette($custom-success, 500-contrast);
}

.mat-danger {
background-color: material.get-color-from-palette($custom-danger, 500);
color: material.get-color-from-palette($custom-danger, 500-contrast);
}

I also removed the map.deep-merge, which was not necessary in this solution.


Complete theme.scss file:

// Custom Theming for Angular Material
// For more information: https://material.angular.io/guide/theming
@use "@angular/material" as material;

@include material.core();

$app-primary: material.define-palette(material.$purple-palette);
$app-accent: material.define-palette(material.$teal-palette, A200);
$app-warn: material.define-palette(material.$red-palette);
// extra Colors
$custom-success: material.define-palette(material.$green-palette);
$custom-danger: material.define-palette(material.$orange-palette);

$custom-theme: material.define-light-theme(
(
color: (
primary: $app-primary,
accent: $app-accent,
warn: $app-warn,
),
)
);

@include material.all-component-themes($custom-theme);

.mat-success {
background-color: material.get-color-from-palette($custom-success, 500);
color: material.get-color-from-palette($custom-success, 500-contrast);
}

.mat-danger {
background-color: material.get-color-from-palette($custom-danger, 500);
color: material.get-color-from-palette($custom-danger, 500-contrast);
}

Github Demo Link (unfortunately Stacklitz has problems with the custom theme)

Angular 2 Material theme refer to color in SCSS

You'll want to use the mat-color($primary) function from @angular/material/core/theming/_theming.scss. That takes in the palette and returns the color.

how to modify the angular material theme main color

Here's a very descriptive guide on how to define your own theme (but you should definitely check out the link that @br.julien posted above.):

NOTE: If you're in a rush, just scroll down to the bottom of this answer to get the whole source code.

Prerequsites

  • If you're using a CSS file, please change the filename extension to .scss.
  • If you're using the Angular CLI, in your styles array, change styles.css to styles.scss:

    "styles": [
    "styles.scss" // <- Change to this
    ]

Get started

  1. Import ~@angular/material/theming at the top of your styles.scss:

    @import '~@angular/material/theming';
  2. After that, add @include mat-core() in styles.scss, ideally after the import line:

    @include mat-core();
  3. Afterwards, define some variables for your app (primary, accent and optionally warn), then assign them to a function called mat-palette:

    // I suggest that you should use another prefix, but `my-app` is fine as well
    // Primary colour
    $my-app-primary: mat-palette($mat-indigo);
    // Accent colour
    $my-app-accent: mat-palette($mat-pink, A200, A100, A400);

    For all palettes, visit the source code (_palette.scss).

    Also, see what the colour palettes look like on Material.io guidelines.

  4. Next, define another variable for your app's theme and include the theme as a parameter of angular-material-theme (place this after the variables you defined above):

    (Note: Choose any one of these options below:)

    Light theme:

    $my-app-theme: mat-light-theme($my-app-primary, $my-app-accent);
    @include angular-material-theme($my-app-theme);

    Dark theme:

    $my-app-theme: mat-dark-theme($my-app-primary, $my-app-accent);
    @include angular-material-theme($my-app-theme);
  5. You're done!

Full source code

Here's some full source code for you to copy :)

styles.scss

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

$my-app-primary: mat-palette($mat-indigo);
$my-app-accent: mat-palette($mat-pink, A200, A100, A400);
$my-app-theme: mat-light-theme($my-app-primary, $my-app-accent);

@include angular-material-theme($my-app-theme);

(Wow. All this work for just 8 lines of code.)

Anyways, if you want to learn more about Sass, check out the official documentation!



Related Topics



Leave a reply



Submit