Scenario
We followed this tutorial to provide our users a dark and a light theme.
Problem
The browser loads the expected css-File (dark or light). Nevertheless, the styles are not applied to our components.
This happens in <head></head>:
<link rel="stylesheet" type="text/css" href="theme-dark.css">
or
<link rel="stylesheet" type="text/css" href="theme-light.css">
As you can see, the browser correctly switches the two themes.
Code
angular.json
"styles": [
"projects/menu/src/styles.scss",
{
"input": "projects/menu/src/theming/theme-dark.scss",
"bundleName": "theme-dark",
"inject": false
},
{
"input": "projects/menu/src/theming/theme-light.scss",
"bundleName": "theme-light",
"inject": false
}
],
theme-service.ts
private _mainTheme$: BehaviorSubject<string> = new BehaviorSubject(
'theme-light'
);
private _darkMode$: BehaviorSubject<boolean> = new BehaviorSubject(false);
darkMode$: Observable<boolean> = this._darkMode$.asObservable();
private _renderer: Renderer2;
private head: HTMLElement;
private themeLinks: HTMLElement[] = [];
theme$: Observable<[string, boolean]>;
constructor(
rendererFactory: RendererFactory2,
@Inject(DOCUMENT) document: Document
) {
this.head = document.head;
this._renderer = rendererFactory.createRenderer(null, null);
this.theme$ = combineLatest([this._mainTheme$, this._darkMode$]);
this.theme$.subscribe(async ([mainTheme, darkMode]) => {
const cssExt = '.css';
const cssFilename = darkMode
? 'theme-dark' + cssExt
: mainTheme + cssExt;
await this.loadCss(cssFilename);
if (this.themeLinks.length == 2)
this._renderer.removeChild(this.head, this.themeLinks.shift());
});
}
setMainTheme(name: string) {
this._mainTheme$.next(name);
}
setDarkMode(value: boolean) {
this._darkMode$.next(value);
}
private async loadCss(filename: string) {
return new Promise((resolve) => {
const linkEl: HTMLElement = this._renderer.createElement('link');
this._renderer.setAttribute(linkEl, 'rel', 'stylesheet');
this._renderer.setAttribute(linkEl, 'type', 'text/css');
this._renderer.setAttribute(linkEl, 'href', filename);
this._renderer.setProperty(linkEl, 'onload', resolve);
this._renderer.appendChild(this.head, linkEl);
this.themeLinks = [...this.themeLinks, linkEl];
});
}
theme-base.scss
@import '~@angular/material/theming';
@include mat-core();
@mixin theming($theme) {
@include angular-material-theme($theme);
}
theme-dark.scss
@import '~@angular/material/theming';
@import './theme-base';
@include mat-core();
// color palette definitions
$primary: mat-palette($dark-md-mcgpaletteblack);
$accent: mat-palette($md-mcgpalettewhite);
$warn: mat-palette($dark-md-mcgpalettered);
$background:mat-palette($dark-md-mcgpalettebackground);
$confirm: mat-palette($dark-md-mcgpaletteorange);
$theme-dark: mat-dark-theme((color: (primary: $primary,
accent: $accent,
warn: $warn,
background: $background,
confirm: $confirm)));
theme-dark.scss - looks the same
In style.scss we import both themes:
styles.scss
@import 'projects/menu/src/theming/theme-dark.scss';
@import 'projects/menu/src/theming/theme-light.scss';
.theme-dark {
@include angular-material-theme($theme-dark)
}
.theme-light {
@include angular-material-theme($theme-light)
}
and then we use those variables:
styles.scss
body {
background: mat-color($background, default);
}
h1 {
color: mat-color($accent, default);
}
But currently we also import them in our components. I think this is one thing, that is wrong.
A dialog would look like this:
@import 'projects/menu/src/theming/theme-dark.scss';
@import 'projects/menu/src/theming/theme-light.scss';
.theme-dark {
@include angular-material-theme($theme-dark)
}
.theme-light{
@include angular-material-theme($theme-light)
}
.mat-button {
color: mat-color($accent, default);
background-color: mat-color($confirm, default);
}
What I tried:
- Removing the import of both themes in every stylesheet. Colors are still influenced by the order of the theme import in
style.scss. Dark theme last -> dark theme will be used and the other way round. - Using the same variables for the themes as in the tutorial. But then we had to change of all of the
background-color: mat-color($confirm, default); - And so on. Spent lots of time...
We can't figure out how to put the missing parts together. Do we need to use mixins? Or are we missing setting the class dark-theme on the root component?
Thank you very much in advance.