55
votes

I am building an angular2 app using angular material2. I am trying to set the background of my application "the correct way", but I can't figure out how.

I found a class I can use on my <body> element: mat-app-background which I can add, that gives me a default color (depending on whether I'm using the light or dark themes).

I wish to define this background color to use my brands' color, but I cannot figure out how to do it.

In _theming.scss it is defined like so:

// Mixin that renders all of the core styles that depend on the theme.
@mixin mat-core-theme($theme) {
  @include mat-ripple-theme($theme);
  @include mat-option-theme($theme);
  @include mat-pseudo-checkbox-theme($theme);

  // Wrapper element that provides the theme background when the
  // user's content isn't inside of a `md-sidenav-container`.
  .mat-app-background {
    $background: map-get($theme, background);
    background-color: mat-color($background, background);
  }
  ...
}

So I thought it would make sense to try adding the background color to my custom theme, somehow, but I couldn't understand how to do so.

On the Material2 theming documentation it only says:

"In Angular Material, a theme is created by composing multiple palettes. In particular, a theme consists of:

  • A primary palette: colors most widely used across all screens and components.
  • An accent palette: colors used for the floating action button and interactive elements.
  • A warn palette: colors used to convey error state.
  • A foreground palette: colors for text and icons.
  • A background palette: colors used for element backgrounds. "

How can I add my background to the theme, or do it in any other way?

11
Would you consider accepting an answer if any of them seem particularly helpful? - Jake Stoeffler
@JakeStoeffler Sure, although I cannot verify it works since we've abandoned our Angular project, and I can't even remember what we ended up doing in the end ^_^ - Narxx

11 Answers

76
votes

If you want to change the theme's background color for the entire app in a clean way, you can override your theme with the following.

// Set custom background color
$custom-background-color: map_get($mat-blue-grey, 50);

// -or- Can set colour by hex value too
$custom-background-color: #628cc9;

$background: map-get($theme, background);
$background: map_merge($background, (background: $custom-background-color));
$theme: map_merge($theme, (background: $background));

This assumes you have already set up your $theme using mat-light-theme or mat-dark-theme. Of course you can substitute $mat-blue-grey for a color map of your choosing.

Here is a full example of how I am using this. I have the following in a file called theme.scss, which is included in my angular.json "styles" entry:

// 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.
$primary: mat-palette($mat-red, 600, 400, 900);
$accent: mat-palette($mat-blue-grey, 500, 200, 700);
$background-color: map_get($mat-blue-grey, 50);

// The warn palette is optional (defaults to red).
$warn: mat-palette($mat-blue);

// Create the theme object (a Sass map containing all of the palettes).
$theme: mat-light-theme($primary, $accent, $warn);

// Insert custom background color
$background: map-get($theme, background);
$background: map_merge($background, (background: $background-color));
$theme: map_merge($theme, (background: $background));

// 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($theme);
@include my-app-theme($theme);
24
votes

Not exactly answer to your question, but I guess many people will end up here searching for "how to set app background color".

In your project/index.html set your body class to mat-app-background

<body class="mat-app-background">
  <app-root></app-root>
</body>

And make sure in your project/angular.json you have:

        "styles": [
          "./node_modules/@angular/material/prebuilt-themes/YOUR_STYLE.css",
          ...
        ],
13
votes

edit: This strategy involves replacing Material functionality. for most cases, I would recommend Jake Stoeffler's answer above.

If you want to set the background colors, you likely want to customize the entire background and foreground palette by emulating the mat-light-theme or mat-dark-theme functions with your own replacement. Your replacement would include your own palettes instead of the mat-light-theme-foreground and background palettes.

example: https://stackblitz.com/edit/angular-material-custom-background?file=theme.scss

I don't know if this method is recommended or officially supported.

6
votes

see : palette theme scss on github Angular (2) Material (2)

Extract of the code:

// Background palette for light themes.
$mat-light-theme-background: (
  status-bar: map_get($mat-grey, 300),
  app-bar:    map_get($mat-grey, 100),
  background: map_get($mat-grey, 50),
  hover:      rgba(black, 0.04), // TODO(kara): check style with Material Design UX
  card:       white,
  dialog:     white,
  disabled-button: $black-12-opacity,
  raised-button: white,
  focused-button: $black-6-opacity,
  selected-button: map_get($mat-grey, 300),
  selected-disabled-button: map_get($mat-grey, 400),
  disabled-button-toggle: map_get($mat-grey, 200),
);

// Background palette for dark themes.
$mat-dark-theme-background: (
  status-bar: black,
  app-bar:    map_get($mat-grey, 900),
  background: #303030,
  hover:      rgba(white, 0.04), // TODO(kara): check style with Material Design UX
  card:       map_get($mat-grey, 800),
  dialog:     map_get($mat-grey, 800),
  disabled-button: $white-12-opacity,
  raised-button: map-get($mat-grey, 800),
  focused-button: $white-6-opacity,
  selected-button: map_get($mat-grey, 900),
  selected-disabled-button: map_get($mat-grey, 800),
  disabled-button-toggle: map_get($mat-grey, 1000),
);

// Foreground palette for light themes.
$mat-light-theme-foreground: (
  base:              black,
  divider:           $black-12-opacity,
  dividers:          $black-12-opacity,
  disabled:          rgba(black, 0.38),
  disabled-button:   rgba(black, 0.38),
  disabled-text:     rgba(black, 0.38),
  hint-text:         rgba(black, 0.38),
  secondary-text:    rgba(black, 0.54),
  icon:              rgba(black, 0.54),
  icons:             rgba(black, 0.54),
  text:              rgba(black, 0.87),
  slider-off:        rgba(black, 0.26),
  slider-off-active: rgba(black, 0.38),
);

// Foreground palette for dark themes.
$mat-dark-theme-foreground: (
  base:              white,
  divider:           $white-12-opacity,
  dividers:          $white-12-opacity,
  disabled:          rgba(white, 0.3),
  disabled-button:   rgba(white, 0.3),
  disabled-text:     rgba(white, 0.3),
  hint-text:         rgba(white, 0.3),
  secondary-text:    rgba(white, 0.7),
  icon:              white,
  icons:             white,
  text:              white,
  slider-off:        rgba(white, 0.3),
  slider-off-active: rgba(white, 0.3),
);
4
votes

Lately, from Material 10.x onwards, the theming methods are getting revamped. With the new approach mat-light-theme or mat-dark-theme only accepts a config object for colors. This is what I've found in the comments :

Previously in Angular Material, theme objects contained the color configuration directly. With the recent refactoring of the theming system to allow for density and typography configurations, this is no longer the case.

At the moment these methods support legacy approach as well, but I hope soon that will be declared as a breaking change. Since we can't merge the new background to theme object as before, the accepted answer might not work anymore.

What I did instead of that, I've updated the $mat-light-theme-background pallete with my custom background, before creating the new theme and that did the job.

$app-primary: mat-palette($md-light);
$app-accent: mat-palette($mat-pink, A200, A100, A400);
$app-warn: mat-palette($mat-red);
$custom-background-color: map_get($md-light, 50);

$mat-light-theme-background: map_merge($mat-light-theme-background, (background: $custom-background-color));

$light-theme: mat-light-theme((
    color: (
        primary: $app-primary,
        accent: $app-accent,
        warn:  $app-warn
    )
));

Note: $md-light is the custom pallet that I have defined for my application, you could use any other values. Also I have tried passing 'background' along with the other color properties which didn't work some reason.

The way themes are included is also slightly changed. Now there is new method called angular-material-color for including the themes.

@include angular-material-color($light-theme);
3
votes

There is also a mixing for colors like this:

.your-class-here {
   background: mat-color($mat-grey, 700, 0.9);
}

When looking at angular material components you can assign a color like this.

<md-toolbar color="primary">
</md-toolbar>

That will make your toolbar the color of your primary color.

also make sure to look at _theming.scss file in angular material.

so you can use those mixins to just pull a color from your palette.

1
votes

There is no way to do it "properly" - only workarounds and hacks. Your theme can define primary, secondary, and warn palettes, but not foreground and background palettes. The probable reason why there isn't a direct/easy way to do this in Angular Material is that according to Material Design you shouldn't do this. Color is meant to be used in a specific way to highlight and style various elements according to your theme, but background and foreground colors for plain content is meant to be either dark or light grey - not colored. If you really need to do this, the other suggestions about redefining the background theme or using your own class should be sufficient.

1
votes

I found that the accepted solution does not work for angular 9. But with a little adjustment, you can make it work.

The original question was how to add a background-color variable to a custom material theme. You can do the following.

styles.scss

// Only import this one time in your project
@include mat-core;

@import '~@angular/material/theming';

// Divine what you want the 'default' variables to look like
$primary: mat-palette($mat-grey, 700, 300, 900);
$accent: mat-palette($mat-blue-grey, 400);
$warn: mat-palette($mat-red, 500);

// create a theme. This can be mat-dark-theme or mat-light-theme
$theme: mat-dark-theme(
  $primary,
  $accent,
  $warn
);

/* This is where you create your custom variable map
Make sure that the variable name you chose is one that does not exist in 
the $theme map. In the accept answer, it uses $background but this one is 
already taken. By using for example, 'background-of-main' you are sure 
that there is no collision */
// You can choose any #hexa color code you want
$custom-variables: (background-of-main: #48494d);

// Merge theme and the custom variables together
$theme: map_merge($theme, $custom-variables);

// Expose custom theme globally
@include angular-material-theme($theme);

In the component where you want to use the background variable, you can do the following. I create a separate file for the code below called:

<path-to-component>/custom-background-component-theme.scss

@import '~@angular/material/theming';

@mixin custom-background-component-theme($theme) {
  $background: map-get($theme, background-of-main);

  <css-selector> {
    background-color: $background;
  }

The final step is to call the custom-background-component-theme mixin in the styles.scss. Therefore the final version of the styles.scss is:

styles.scss

// Only import this one time in your project
@include mat-core;

@import '~@angular/material/theming';

// Divine what you want the 'default' styles to look like
$primary: mat-palette($mat-grey, 700, 300, 900);
$accent: mat-palette($mat-blue-grey, 400);
$warn: mat-palette($mat-red, 500);

// create a theme. This can be mat-dark-theme or mat-light-theme
$theme: mat-dark-theme(
  $primary,   
  $accent,
  $warn
);

/* This is where you create your custom variable map
Make sure that the variable name you chose is one that does not exist in 
the $theme map. In the accept answer, it uses $background but this one is 
already taken. By using for example, 'background-of-main' you are 
sure that there is not collision */
// You can choose any #hexa color code you want
$custom-variables: (background-of-main: #48494d);

// Merge theme and the custom variables together
$theme: map_merge($theme, $custom-variables);

// Expose custom theme globally
@include angular-material-theme($theme);

// Import custom mixin
@import './<path-to-component>/custom-background-component-theme.scss';

// Insert custom theme into component styling
@include custom-background-component-theme($theme);

This should do the job!

0
votes

I would suggest that you declare a background colour in a variables file (assuming you're using sass) then simply import it where needed. For example:-

@import '../config/variables';

body {
    height: 100%;
    margin: 0;
    background-color: $brand-primary;
}
0
votes

for extra solution if previous didn't work i angular material 2 working with encapsulation style so whatever you gonna do you can't customize angular material component from outside so an ideal solution for that i always use try this

1- you can use this hack that gonna give you possibilities to customize angular material component if you want to by set ViewEncapsulation.None

//test.component.ts
import { ViewEncapsulation } from '@angular/core';
@Component({
  selector: 'app-test',
  templateUrl: '.....',
  styleUrls: ['....'],
  encapsulation: ViewEncapsulation.None
})

or

2- if you want just to change background you can simple try this

//style.css (main style file)
html, body {
  background-color: #fafafa;
}

this gonna change the whole background color of all your app

0
votes

A little late to the party. I know this is Angular Material 2 but, google leads here material. Adding my findings.

Angular Material does make it a little hard to change background and foreground styles in Material 11.2. I dug through the theme files to see how it all works.

To change the theme background. Let's say you have core.scss file that has your theme related styles. Material Doc

$candy-app-primary: mat-palette($mat-indigo);
$candy-app-accent:  mat-palette($mat-pink, A200, A100, A400);
$candy-app-warn:    mat-palette($mat-red);

you change the theme background by modifying $mat-light-theme-background for light theme and dark for dark theme. Use map-merge to prevent unwanted issues.

$mat-light-theme-background: map-merge($mat-light-theme-background, (
   app-bar: map-get($mat-grey, A100), // Change color to whatever you want.
   background: map-get($mat-grey, A100) // Change color to whatever you want. 
));

// Follow by calling mat-light-theme(//) or mat-dark-theme(//)

This will change the background of the Angular application.