Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you apply an Angular themes primary color to a div?

Is there a way to theme an Angular 7 application, so that you can:

  • Apply theming to normal HTML elements too and not just Angular Material components
  • Switch the theme at runtime
  • Don't have to use a class for every color and every type of usage (color, background-color, border-color, ...), like in some other questions and solutions.

For Example

I want to do something like this:

<div color="primary">

</div>

But that does not work, because the color attribute is only for angular material components.

Also, I want to be able to change the background color, text color, and so on, depending on the current theme. (Dark theme, Light theme)

like image 978
MauriceNino Avatar asked Sep 11 '25 20:09

MauriceNino


1 Answers

About the solution

With this solution you can:

  • Switch the theme during runtime
  • Get the current theme during runtime
  • Theme directly in CSS without the usage of extra classes or anything
  • Have an easy to use and easy to understand solution, that only requires a one time setup

Cons:

  • Uses CSS variables. Some older browsers might not support them
  • Relies on newer Angular versions. I don't know if this would work in older versions (Tested in Angular 6 & 7)

This is what I am using in my project right now:

Setup

First you need to define a theme.

Here is an example called dark-theme.scss located in src/themes:

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

// Set variables to whatever colors you want for your app
$dark-theme-primary: mat-palette($mat-pink);
$dark-theme-accent: mat-palette($mat-light-blue);
$dark-theme-warn: mat-palette($mat-red);

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

@include angular-material-theme($dark-theme);

Then you need a SCSS function that can create theme SCSS and CSS variables:

Here is mine called functions.scss in src/assets/scss:

@mixin generate-theme-vars($theme) {
  //default palette foreground/background:
  $foreground-palette: map-get($theme, foreground);
  $background-palette: map-get($theme, background);

  /////////////////////////////////////////////////
  // SCSS VARS
  /////////////////////////////////////////////////

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

  $base: mat-color($foreground-palette, base);
  $divider: mat-color($foreground-palette, divider);
  $dividers: mat-color($foreground-palette, dividers);
  $disabled: mat-color($foreground-palette, disabled);
  $disabled-button: mat-color($foreground-palette, disabled-button);
  $disabled-text: mat-color($foreground-palette, disabled-text);
  $hint-text: mat-color($foreground-palette, hint-text);
  $secondary-text: mat-color($foreground-palette, secondary-text);
  $icon: mat-color($foreground-palette, icon);
  $icons: mat-color($foreground-palette, icons);
  $text: mat-color($foreground-palette, text);
  $slider-off: mat-color($foreground-palette, slider-off);
  $slider-off-active: mat-color($foreground-palette, slider-off-active);
  
  $status-bar: mat-color($background-palette, status-bar);
  $app-bar: mat-color($background-palette, app-bar);
  $background: mat-color($background-palette, background);
  $hover: mat-color($background-palette, hover);
  $card: mat-color($background-palette, card);
  $dialog: mat-color($background-palette, dialog);
  $disabled-button: mat-color($background-palette, disabled-button);
  $raised-button: mat-color($background-palette, raised-button);
  $focused-button: mat-color($background-palette, focused-button);
  $selected-button: mat-color($background-palette, selected-button);
  $selected-disabled-button: mat-color($background-palette, selected-disabled-button);
  $disabled-button-toggle: mat-color($background-palette, disabled-button-toggle);

  /////////////////////////////////////////////////
  // CSS VARS
  /////////////////////////////////////////////////


  --primary-color: #{$primary};
  --accent-color: #{$accent};
  --warn-color: #{$warn};

  --base-color: #{$base};
  --divider-color: #{$divider};
  --dividers-color: #{$dividers};
  --disabled-color: #{$disabled};
  --disabled-text-color: #{$disabled-text};
  --hint-text-color: #{$hint-text};
  --secondary-text-color: #{$secondary-text};
  --icon-color: #{$icon};
  --icons-color: #{$icons};
  --text-color: #{$text};
  --slider-off-color: #{$slider-off};
  --slider-off-active-color: #{$slider-off-active};

  --status-bar-color: #{$status-bar};
  --app-bar-color: #{$app-bar};
  --background-color: #{$background};
  --hover-color: #{$hover};
  --card-color: #{$card};
  --dialog-color: #{$dialog};
  --disabled-button-color: #{$disabled-button};
  --raised-button-color: #{$raised-button};
  --focused-button-color: #{$focused-button};
  --selected-button-color: #{$selected-button};
  --selected-disabled-button-color: #{$selected-disabled-button};
  --disabled-button-toggle-color: #{$disabled-button-toggle};
}

After that, you are all set and all you have to do is to create a class for every theme in your global styles.scss:

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

// You have to define one of those for every theme you offer
.dark-theme {
    @import "themes/dark-theme";
    @include angular-material-theme($dark-theme);
    @include generate-theme-vars($dark-theme);
}

.light-theme {
    @import "themes/light-theme";
    @include angular-material-theme($light-theme);
    @include generate-theme-vars($light-theme);
}

Usage

To apply the theme you want to use, you need to put the CSS class dark-theme (or whatever you called it) to an element that contains all other elements.

I put it to the HTML tag:

<!doctype html>
<html lang="en" class="dark-theme">
    <!-- ... -->
</html>

Now you can switch the theme on runtime, by changing that class with JavaScript to light-theme for example.

In every CSS property that wants a color, you can use variables now:

div {
    width: 300px;
    height: 300px;

    background-color: var(--app-bar-color);

    .someText {
        color: var(--text-color);
    }
}

If you want to do something in your CSS if a special theme is applied and the change is not the color itself, then do it like this:

// Example: We want to remove some div only when the light-theme is used
div {
    width: 300px;
    height: 300px;

    background-color: var(--app-bar-color);

    
    :host-context(.light-theme) & {
        display: none;
    }
}

PS

For everyone who might wonder why I am using @import "functions";, even though they are in different folders:

Go into angular.json and add to the object projects > <YourProject> > architect > build > options the following:

"stylePreprocessorOptions": {
    "includePaths": [
    "src/assets/scss"
    ]
},

Now you can use @import "functions"; from every path.

In case you need to support IE (untested, might need work)

So if you can't use CSS variables on some clients, you can define a fallback for the specified colors like so:

div {
    background-color: red; // fallback to red if the variable doesnt exist -> Old browsers, or IE
    background-color: var(--app-bar-color);
}

With this knowledge, you could for example define a few SCSS variables in styles.scss:

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

// Default theme
@import "themes/dark-theme";
@include angular-material-theme($dark-theme);

// Generate SCSS vars
$foreground-palette: map-get($theme, foreground);
$background-palette: map-get($theme, background);

/////////////////////////////////////////////////
// SCSS VARS
/////////////////////////////////////////////////

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

// ... and all the other vars from above if you would like


// You have to define one of those for every theme you offer
.dark-theme {
    // Only init the CSS vars here, because the rest is in default
    @include generate-theme-vars($dark-theme);
}

.light-theme {
    @import "themes/light-theme";
    @include angular-material-theme($light-theme);
    @include generate-theme-vars($light-theme);
}

Now you could use it like this:

div {
    background-color: $primary; // fallback
    background-color: var(--primary-color);
}

This cant be changed dynamically with JS during the runtime anymore though!!

like image 166
MauriceNino Avatar answered Sep 14 '25 09:09

MauriceNino