Components: Add docs on how to set background in theme

Created on 3 Aug 2017  路  14Comments  路  Source: angular/components

Bug, feature request, or proposal:

proposal

What is the expected behavior?

Add documentation on how to set background in a custom theme to https://material.angular.io/guide/theming

What is the current behavior?

No docs

What are the steps to reproduce?

https://material.angular.io/guide/theming

Providing a Plunker (or similar) is the best way to get the team to see your issue.
Plunker template: https://goo.gl/DlHd6U

What is the use-case or motivation for changing an existing behavior?

Makes it easier to customise themes

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

Is there anything else we should know?

P4 theming docs help wanted

Most helpful comment

Would be nice if those 2 functions were similar to how red has defaults to allow overriding without copy/pasting:

// Creates a container object for a light theme to be given to individual component theme mixins.
@function mat-light-theme($primary, $accent, $warn: mat-palette($mat-red), $foreground: mat-palette($mat-light-theme-foreground), $background: mat-palette($mat-light-theme-background)) {
  @return (
    primary: $primary,
    accent: $accent,
    warn: $warn,
    is-dark: false,
    foreground: $foreground,
    background: $background,
  );
}

// Creates a container object for a dark theme to be given to individual component theme mixins.
@function mat-dark-theme($primary, $accent, $warn: mat-palette($mat-red), $foreground: mat-palette($mat-dark-theme-foreground), $background: mat-palette($mat-dark-theme-background)) {
  @return (
    primary: $primary,
    accent: $accent,
    warn: $warn,
    is-dark: true,
    foreground: $foreground,
    background: $background,
  );
}

Or better yet, just don't use those functions:

$my-dark-theme: (
  primary: $my-primary,
  accent: $my-accent,
  warn: $my-warn,
  is-dark: true,
  foreground: $my-dark-theme-foreground,
  background: $my-dark-theme-background,
);

$my-light-theme: (
  primary: $my-primary,
  accent: $my-accent,
  warn: $my-warn,
  is-dark: false,
  foreground: $my-light-theme-foreground,
  background: $my-light-theme-background,
);

To be honest whilst reading into all of the helpers the mat-light-theme() and mat-dark-theme() functions add an extra layer of complexity that doesn't add anything IMO

All 14 comments

Should developers be encouraged to set background colors of a theme? Or do we just want documentation on using the background color from a theme?

put differently:
Do we want to (a) show people how to change the value of map-get($theme, background), or do we want to (b) document that map-get($theme, background) can be used?

@literalpie : I'd like to know how to set background colors of a theme when I create it.

@fabienbranchel
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 - therefore, I'm not sure if it should be added to the documentation. It seems to me like it would be a better fit for a blog post.

Would be nice if those 2 functions were similar to how red has defaults to allow overriding without copy/pasting:

// Creates a container object for a light theme to be given to individual component theme mixins.
@function mat-light-theme($primary, $accent, $warn: mat-palette($mat-red), $foreground: mat-palette($mat-light-theme-foreground), $background: mat-palette($mat-light-theme-background)) {
  @return (
    primary: $primary,
    accent: $accent,
    warn: $warn,
    is-dark: false,
    foreground: $foreground,
    background: $background,
  );
}

// Creates a container object for a dark theme to be given to individual component theme mixins.
@function mat-dark-theme($primary, $accent, $warn: mat-palette($mat-red), $foreground: mat-palette($mat-dark-theme-foreground), $background: mat-palette($mat-dark-theme-background)) {
  @return (
    primary: $primary,
    accent: $accent,
    warn: $warn,
    is-dark: true,
    foreground: $foreground,
    background: $background,
  );
}

Or better yet, just don't use those functions:

$my-dark-theme: (
  primary: $my-primary,
  accent: $my-accent,
  warn: $my-warn,
  is-dark: true,
  foreground: $my-dark-theme-foreground,
  background: $my-dark-theme-background,
);

$my-light-theme: (
  primary: $my-primary,
  accent: $my-accent,
  warn: $my-warn,
  is-dark: false,
  foreground: $my-light-theme-foreground,
  background: $my-light-theme-background,
);

To be honest whilst reading into all of the helpers the mat-light-theme() and mat-dark-theme() functions add an extra layer of complexity that doesn't add anything IMO

I have also struggled to find a way to set the app background, and unfortunately the proposed solutions do not work if the app is not wrapped in a material component.

For example, in @literalpie 's example, the app is wrapped inside a mat-sidenav-container component.

The only way i have found to set the background for app-root, is to inculde the following in your styles.scss file (or whatever the name of the file that you declare on your angular.json definition)

app-root {
  background: map-get($mat-dark-theme-background, background );
}

That will work, provided that you have declared the $mat-dark-theme-background map, and it is helpful because you keep your background color declared in one place (theme.scss).

Of course you can provide any color, that is independent of the theme you have created, but this might be harder to maintain.

@ktsangop I think you're missing this:

Finally, if your app's content is not placed inside of a mat-sidenav-container element, you need to add the mat-app-background class to your wrapper element (for example the body). This ensures that the proper theme background is applied to your page.

source

@intellix

To be honest whilst reading into all of the helpers the mat-light-theme() and mat-dark-theme() functions add an extra layer of complexity that doesn't add anything IMO

Are you saying that instead of having the two functions, someone would use the dark theme by passing the foreground and background? I could get on board with that.

@ktsangop I think you're missing this:

Finally, if your app's content is not placed inside of a mat-sidenav-container element, you need to add the mat-app-background class to your wrapper element (for example the body). This ensures that the proper theme background is applied to your page.

source

馃う鈥嶁檪 OK, i have totally missed that! 馃ぃ

FWIW, my solution, applies the background color even before the app.component is bootstraped, which in my case makes a custom loading spinner i have, being displayed using the theme background color.

Instead, adding the mat-app-background class to the <body> does not have the same effect.

i am trying to use angular material with a theme built in scss,angular,bootstrap , i have install it using npm and add all the neccessary files, also it is not showing any error yet i am not able to use it components

Just add Material theming in your angular project.

ng add @angular/material

then choose custom theming option and paste the below code you will get black dark theming and if you wanna customize material color scheme then go to https://material.io and go material color palette and select your custom color scheme for your navbar and button(other components).

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

$custom-typography: mat-typography-config(
$font-family:
"-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif"
);

@include mat-core($custom-typography);

$your-app-name-primary: mat-palette($mat-purple, 200);
$your-app-name-accent: mat-palette($mat-teal, 200);
$your-app-name-warn: mat-palette($mat-red);
$your-app-name-theme: mat-dark-theme(
$your-app-name-primary,
$your-app-name-accent,
$your-app-name-warn
);

@include angular-material-theme($your-app-name-theme);

Just found this thread. I've been trying to figure out themes for a long time. Couldn't find a concrete solution until now. Making it work by adding <mat-sidenav-container> over the app. So thank you @literalpie . But can you give an example of how to add the mat-app-background to the _body_ element?

However, if I don't have enough content on the window then the rest of the background remains white(default color) only. So you would need to modify the style of <mat-sidenav-container> to max out it's height. You can see the app.component.css to look at what I've done.

I have applied the theme toggle in my header and as per Angular Material docs, added an extra class to the div wrapper by adding an _id_ and modifying it's style in theme.service.ts.

custom_theme.scss

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

// LIGHT THEME

$light-primary: mat-palette($mat-indigo);
$light-accent: mat-palette($mat-yellow, A200, A100, A400);
$light-warn: mat-palette($mat-red);
$light-theme: mat-light-theme($light-primary, $light-accent, $light-warn);
@include angular-material-theme($light-theme);

// DARK THEME

$dark-primary: mat-palette($mat-grey);
$dark-accent: mat-palette($mat-amber, A200, A100, A400);
$dark-warn: mat-palette($mat-red);
// Create the theme object (a Sass map containing all of the palettes).
$dark-theme: mat-dark-theme($dark-primary, $dark-accent, $dark-warn);

.dark-theme {
  @include angular-material-theme($dark-theme);
}

app.component.html

<div id="alternative-theme">
  <mat-sidenav-container class="app-container">
    <app-header></app-header>
    <router-outlet> </router-outlet>
    <app-footer></app-footer>
  </mat-sidenav-container>
</div>

app.component.css

#alternative-theme {
  display: block;
  height: 100%;
}

.app-container {
  height: inherit;
}

theme.service.ts

import { Injectable } from "@angular/core";
import { OverlayContainer } from "@angular/cdk/overlay";

@Injectable({
  providedIn: "root"
})
export class ThemeService {
  constructor(private overlayContainer: OverlayContainer) {
    this.overlayContainer = overlayContainer;
  }

  setDarkTheme() {
    document.getElementById("alternative-theme").classList.add("dark-theme");
    document.getElementById("footer-text").classList.remove("dark");
    this.overlayContainer.getContainerElement().classList.add("dark-theme");
  }

  setLightTheme() {
    document.getElementById("alternative-theme").classList.remove("dark-theme");
    document.getElementById("footer-text").classList.add("dark");
    this.overlayContainer.getContainerElement().classList.remove("dark-theme");
    document;
  }
}

_Is this the best way to toggle between themes or is there a more robust way?_ I'm just starting with Angular and Material UI and if you have anything to add to the above snippets to make it better will be appreciated. Cheers.

@nair-ayush

Just put the classes on your body or app:

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

@see https://material.angular.io/guide/theming#using-a-pre-built-theme

Finally, if your app's content is not placed inside of a mat-sidenav-container element, you need to add the mat-app-background class to your wrapper element (for example the body). This ensures that the proper theme background is applied to your page.

Adding onto @intellix proposal:

It'd be backwards compatible to change the current mat-light-theme (and mat-dark-theme with the proper methods) implementations to call:

@function mat-light-theme(...) {
  // ...
  $result: $primary;
  @if map_get($primary, color) {
    $color-settings: map_get($primary, color);
    $primary: map_get($color-settings, primary);
    $accent: map_get($color-settings, accent);
    $warn: map_get($color-settings, warn);
    $foreground: map_get($color-settings, foreground);
    $background: map_get($color-settings, background);
    $result: map_merge($result, (color: _mat-create-light-color-config($primary, $accent, $warn, $foreground, $background)));
  }
  @return _mat-create-backwards-compatibility-theme(_mat-validate-theme($result));
}

@function _mat-create-light-color-config($primary, $accent, $warn: null, $foreground: $mat-light-theme-foreground, $background: $mat-light-theme-background) {
  @return (
    primary: $primary,
    accent: $accent,
    warn: if($warn != null, $warn, mat-palette($mat-red)),
    is-dark: false,
    foreground: $foreground,
    background: $background,
  );
}

This way, guarantees that people using the older stuff still works (since it defaults to the global variables) and yet people who want can use the cleaner method:

$theme: mat-light-theme((
  color: (
    primary: $primary,
    accent: $accent,
    warn: $warn,
    background: (
      app-bar: #fff,
    ),
  ),
));

Right now the equivalent of the above usage is:

$mat-light-theme-background: map_merge($mat-light-theme-background, (
  app-bar: #fff,
));

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

Hopefully this gets added soon.

It is pretty annoying to being able to set primary, accent and warn palettes, and not being able to set the foreground and background ones in an easy and clean way too.

(Right now using the accepted answer at https://stackoverflow.com/questions/43919927/angular-material2-theming-how-to-set-app-background)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

AlanCrevon picture AlanCrevon  路  107Comments

jelbourn picture jelbourn  路  171Comments

anderflash picture anderflash  路  59Comments

vibingopal picture vibingopal  路  80Comments

mmalerba picture mmalerba  路  77Comments