Change ionic component's background color dynamically [Ionic 4]

Hi,
I created an application which allow the user to change background color in every page of the application.

Button, header, menu, label … are all affected by the user’s choice .
With ionic 3 I was dynamically injecting the style on each components with ngStyle.

<ion-navbar [ngStyle]="style.header">
  <button ion-button icon-only menuToggle [ngStyle]="style.buttonWhite">
    <ion-icon name="menu"></ion-icon>
  </button>

...

</ion-navbar>

style defines differents values for header, button, menu, …

this.header = { 'background-color': StyleService.primary.medium, 'color': 'white' };
this.buttonWhite = { 'color': 'white' };

StyleService.primary.medium will be the dynamic user’s choice.

Since I updated to ionic 4, every ionic component generate children which set the background-color for themeselve

<ion-button [ngStyle]="style.buttonWhite"></ion-button>

become

<ion-button style="color:white">
        <button></button>
</ion-button>

But style on ion level will not affect lowers layers and button color will stay black.

So, is it possible to change dynamically the color of all the ionic composant ?

3 Likes

I finally resolve my issue.
Basically, migration from ionic 3 to ionic 4 changes rules about css. They are now following angular rules.
.scss components files are not global anymore. With default config, it is now not possible to override child component style.
But, there is two ways to deal with that.

  1. View encapsulation
    https://angular.io/api/core/ViewEncapsulation
    With:
 encapsulation: ViewEncapsulation.None

In that case you will create a component affected and which will be affect others components around him. Be careful with that thougt.
2. Global css
use global.scss of your ionic project to add global css properties which will affect all components of your project.

Finally, when you choose one of both solutions, you can use CSS3 variable:

Something like:

// MAIN COLOR
.primaryColor {
  color: var(--primaryColor);
}
.secondaryColor {
  color: var(--accentColor);
}
.dangerColor {
  color: var(--warnColor);
}

And then in a service in charge of your dynamic style:

        const themeWrapper = document.querySelector('body');
        themeWrapper.style.setProperty('--primaryColor', StyleService.primary.medium);
        themeWrapper.style.setProperty('--primaryLightColor', StyleService.primary.light);
        themeWrapper.style.setProperty('--primaryDarkColor', StyleService.primary.dark);

Et voila, you can now override ionic theme with colors store on server

scss override:


// MAIN COLOR
.primaryColor {
  color: var(--primaryColor);
}
.secondaryColor {
  color: var(--accentColor);
}
.dangerColor {
  color: var(--warnColor);
}

// LIGHT
.lightPrimaryColor {
  color: var(--primaryLightColor);
}
.lightSecondaryColor {
  color: var(--accentLightColor);
}

// DARK
.darkPrimaryColor {
  color: var(--primaryDarkColor);
}
.darkSecondaryColor {
  color: var(--accentDarkColor);
}

.whiteColor {
  color: #ffffff;
}
.blackColor {
  color: #000000;
}
.translucide {
    background-color: rgba(0,0,0,0);
    color: white;
}

// BACKGROUND COLOR
.primaryBackColor {
  background-color: var(--primaryColor);
  color: var(--primaryTextColor);
}
.secondaryBackColor {
  background-color: var(--accentColor);
  color: var(--accentTextColor);
}
// LIGHT
.lightPrimaryBackColor {
  background-color: var(--primaryLightColor);
  color: var(--primaryLightTextColor);
}
.lightSecondaryBackColor {
  background-color: var(--accentLightColor);
  color: var(--accentLightTextColor);
}
// DARK
.darkPrimaryBackColor {
  background-color: var(--primaryDarkColor);
  color: var(--primaryDarkTextColor);
}
.darkSecondaryBackColor {
  background-color: var(--accentDarkColor);
  color: var(--accentDarkTextColor);
}
.dangerBackColor {
  background-color: var(--warnColor);
  color: var(--warnTextColor);
}

// FAB BUTTON
.fab-md-secondary,
.fab-ios-secondary {
  background-color: var(--accentColor);
  color: var(--accentTextColor);
}
.fab-md-primary,
.fab-ios-primary {
  background-color: var(--primaryColor);
  color: var(--primaryTextColor);
}
.fab-md-danger,
.fab-ios-danger {
  background-color: var(--warnColor);
  color: var(--warnTextColor);
}

// BUTTON
.button-md-primary,
.button-ios-primary {
  background-color: var(--primaryColor);
  color: var(--primaryTextColor);
}
.button-md-secondary,
.button-ios-secondary {
  background-color: var(--accentColor);
  color: var(--accentTextColor);
}
.button-md-danger,
.button-ios-danger {
  background-color: var(--warnColor);
  color: var(--warnTextColor);
}

// BUTTON OUTLINED AND CLEAR
.button-outline-md-primary,
.button-outline-ios-primary,
.button-clear-md-primary,
.button-clear-ios-primary {
  background-color: "transparent";
  border-color: var(--primaryColor);
  color: var(--primaryColor);
}
.button-outline-md-secondary,
.button-outline-ios-secondary,
.button-clear-md-secondary,
.button-clear-ios-secondary {
  background-color: "transparent";
  border-color: var(--accentColor);
  color: var(--accentColor);
}
.button-outline-md-danger,
.button-outline-ios-danger,
.button-clear-md-danger,
.button-clear-ios-danger {
  background-color: "transparent";
  border-color: var(--warnColor);
  color: var(--warnColor);
}

and service part


    public setAppTheme(theme?: any, saveTheme?: boolean) {
        const themeWrapper = document.querySelector('body');
        // const themeWrapper = document.getElementById('global-mat-sidenav-container');

        themeWrapper.style.setProperty('--primaryColor', StyleService.primary.medium);
        themeWrapper.style.setProperty('--primaryLightColor', StyleService.primary.light);
        themeWrapper.style.setProperty('--primaryDarkColor', StyleService.primary.dark);
        themeWrapper.style.setProperty('--primaryTextColor', StyleService.primary.textColor);
        themeWrapper.style.setProperty('--primaryLightTextColor', StyleService.primary.lightTextColor);
        themeWrapper.style.setProperty('--primaryDarkTextColor', StyleService.primary.darkTextColor);

        themeWrapper.style.setProperty('--accentColor', StyleService.accent.medium);
        themeWrapper.style.setProperty('--accentLightColor', StyleService.accent.light);
        themeWrapper.style.setProperty('--accentDarkColor', StyleService.accent.dark);
        themeWrapper.style.setProperty('--accentTextColor', StyleService.accent.textColor);
        themeWrapper.style.setProperty('--accentLightTextColor', StyleService.accent.lightTextColor);
        themeWrapper.style.setProperty('--accentDarkTextColor', StyleService.accent.darkTextColor);


        themeWrapper.style.setProperty('--warnColor', StyleService.alert);
        themeWrapper.style.setProperty('--warnTextColor', StyleService.alert.textColor);

        // on previens d'une nouvelle image
        // this.themeImage.next(environment.settings.apiUrl + 'accessible/menu/' + theme.menuImage);

        // if (saveTheme) {
        //     this.localStorageService.setItem(LocalStorageEnum.THEME, theme);
        // }
    }
2 Likes

Te rifaste!! Muchas gracias