Angular material 5 dark theme not applied to body
Asked Answered
M

7

21

I've created a "custom" theme, (using the theming documentation at https://material.angular.io/guide/theming, which is pretty bad) like this:

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

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

.indigo-pink {
  @include angular-material-theme($ip-theme);
}

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

My index.html contains this:

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

In the container for the app-root component, I switch between my custom class names (indigo-pink and indigo-pink-dark) using this:

<div [ngClass]="appTheme">

I am also setting the CDK overlay container class to my custom class name using this:

setContainerClass(className: string): void {
  const containerClassToKeep = 'cdk-overlay-container';
  const overlayClassList = this.overlayContainer.getContainerElement().classList;
  const existingClasses = Array.from(overlayClassList);

  existingClasses.forEach(classToken => {
    if (classToken !== containerClassToKeep) {
      overlayClassList.remove(classToken);
    }
  });

  overlayClassList.add(className);
}

The main problem is that when I switch into the dark theme, I do see the indigo-pink-dark class name get added to my app component container correctly, but only some styles change (e.g. the toolbar at the top goes dark, and Material components) - the body of the page stays white. The theming guide (and other blog posts) say that using the mat-app-background should fix this exact problem.

Additionally though, if I try manually update the background-color of the body, using e.g.

.indigo-pink-dark {
  @include angular-material-theme($ip-theme-dark);

  body & {
    background-color: #000;
  }
}

Then this "background-color" just overlays the entire page and you cannot see any elements on the page. This is something to do with the CDK overlay, because if I remove the part that adds the class name to the overlay, it kind of works - the background of the page does get set correctly, but then overlays do not get correct styling.

Mandorla answered 9/4, 2018 at 13:47 Comment(2)
From what I have faced until now (that is similar to your issue), the best solution I've found is to use a sidenav : the mat-sidenav-content gets its background color from the drak theme. If you don't want to use it, you can also use a material card to apply the color. Simply make a card that is all over the body, and remove the border-radius (and padding if you must).Chaotic
Thanks, yes, I have seen this recommended also, but I want to avoid making the whole site a component if possible :)Mandorla
B
25

I had the same issue and found this solution on the Angular Material GitHub issue#3298 (post by JamieStill).

I wrapped all of my app.component.html content in a div

<div class="mat-typography app-frame mat-app-background">
    <app-header></app-header>
    <main>
        <app-post-create></app-post-create>
        <app-post-list></app-post-list>
    </main>
</div>

And in app.component.css

html, body, app-root, .app-frame {
    overflow: hidden;
    margin: 0;
    height: 100%;
    box-sizing: border-box;
    color: #e0e0e0;
}

I've only tested this in a practice app in Angular 6, but I suspect it will work in Angular 5 as well.

Before:

Before

After:

After

Barros answered 7/10, 2018 at 14:59 Comment(2)
Thanks.. the mat-app-background class on the body class did it for me. Before that controls on the main/app component were invisible - only seen on focus. Your tip made the dark theme complete :)Hein
Does it still work if you add a mat-select with mat-option?Staggs
P
13

if you add angular material after your project has started, you simply have to manually add mat-app-background class to your body element in your index.html as below:

<body class="mat-typography mat-app-background">
...
</body>
Peavy answered 6/3, 2021 at 17:2 Comment(1)
This is the best answer for Angular 15 (2023). Just add this class to the body tag.Janettjanetta
M
4

Only vh-100 mat-app-background in app.component.html

<div class="vh-100 mat-app-background">
  <router-outlet></router-outlet>
</div>
Masquerade answered 18/4, 2021 at 8:12 Comment(0)
T
3

I'm not sure why you are you manipulating the CDK overlay container. That seems unnecessary. Just bind your theme classes to the document body. See https://stackblitz.com/edit/angular-ndmju6.

Snippet:

theme: string = 'Light';

constructor(private renderer: Renderer2) {
  this.renderer.addClass(document.body, 'indigo-pink');
}

toggleTheme(): void {

  if (this.theme === 'Light') {
    this.theme = 'Dark';
    this.renderer.addClass(document.body, 'indigo-pink-dark');
    this.renderer.removeClass(document.body, 'indigo-pink');
  } else {
    this.theme = 'Light';
    this.renderer.addClass(document.body, 'indigo-pink');
    this.renderer.removeClass(document.body, 'indigo-pink-dark');
  }
  
}
Tucket answered 9/4, 2018 at 15:40 Comment(4)
Primarily because the documentation says that you have to do this, and partly because overlay components were not being styled correctly before I added that part. The reason it works in the stackblitz is because you're using the sidenav-container component. But I am not using this, and would rather avoid it if possible. But thanksMandorla
Right - I see. I think the problem is class hierarchy. Basically you define all of the Angular Material styling as a child of your light and dark theme classes. This works for the main app element (everything in it is a child), but the overlay element is not a child - it is a sibling. What needs to happen is to have the theme classes applied to <body> so that the overlay element is a child. That would also work for the main app element because it is also a child of <body>.Tucket
Thanks, yes. Unfortunately, the body is outside of the root of my app, and as such I cannot access it with Angular. In NG1x we could make the body the root of the app, but in NG2+ it does not seem possible.Mandorla
Actually you can access it - you can inject the document or renderer object into the constructor of your app controller and add/remove classes (sorry for inline formatting): constructor(private renderer: Renderer2) { this.renderer.addClass(document.body, 'indigo-pink'); }. This won't work in stackblitz I don't think.Tucket
R
3

Late in the game, but try to set height to 100%. This is what fixed it for me. Here dark-theme is a global class that has my Angular Material dark theme in it. I put this HTML in app.component.html.

<div class="mat-app-background dark-theme" style="height: 100%;">
  <app-root></app-root>
</div>

This was using Angular 9.

Registered answered 30/4, 2020 at 1:20 Comment(0)
R
2

EDIT 2024: I found another even easier solution

Just wrap your stuff inside an element with mat-app-background

<body class="theme-light">
  <div class="mat-app-background">
    <app-root></app-root>
  </div>
  //...
</body>

Still Working: Original solutions

A bit late, but there are 2 solutions (as far as i know).

The "problem": themes are supposed to apply on angular material components, nothing else.

Solutions:

1- You either encapsulate your app in a mat-drawer and making sure it has 100% height:

<mat-drawer-container style="height: 100%">
    <mat-drawer-content>
        <router-outlet></router-outlet>
    </mat-drawer-content>
</mat-drawer-container>

2- Another way to do that without having to make your whole app inside a component, is to do it through css (or scss in this case):

body {
    height: 100%;
    &.theme-light {
       background: rgba(0, 0, 0, 0.02) // or whatever light color suits you
    }
     &.theme-black {
       background: rgba(0, 0, 0, 0.87) // or whatever dark color suits you
    }
}

Personnaly, i prefer using mat-drawer. Why ? Because color will be determined by material design background color, so you won't have to handle contrast and other stuff as it is already handled for you.

Roncesvalles answered 11/12, 2021 at 1:54 Comment(0)
W
0

I could not change the default light theme background color, so I hacked it:

// fix background problem

.mat-app-background {
  background-color: white;
}

My dark-theme overrides this so it works fine.

Wherewithal answered 3/10, 2021 at 16:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.