Angular темизация через CSS переменные

В темизации всё более менее понятно, кроме момента как динамически менять значения цветов.

global style.scss

:root {
    --background-color: lightyellow;
    --text-color: darkslategray;
}

*.component.scss

:host {
    display: block;
    background-color: var(--background-color);
    color: var(--text-color);
}

Чтобы поменять цвета необходимо заменить значение --background-color и --text-color. Однако через Renderer2 установить значения не предстваляется возможным.

  constructor(
    private _renderer: Renderer2,
    private _el: ElementRef,
  ) {}

  onChange(): void {
    // затирает `--background-color: black;` 
    this._renderer.setProperty(this._el.nativeElement, 'style', '--background-color: black');
    this._renderer.setProperty(this._el.nativeElement, 'style', '--text-color: red'); 

    // затирает `--background-color: black;`
    this._renderer.setAttribute(this._el.nativeElement, 'style', '--background-color: black');
    this._renderer.setAttribute(this._el.nativeElement, 'style', '--text-color: red'); 

    // вообще не работает т.к. не изменяет неизвестные свойства такие как CSS переменные
    this._renderer.setStyle(this._el.nativeElement, '--background-color', 'black');
    this._renderer.setStyle(this._el.nativeElement, '--text-color', 'red');
  }

binding стилей напрямую также не работает

<hello name="{{ name }}" [ngStyle]="{'--text-color': 'green'}" [style.--text-color]="'blue'"></hello>

Для решения проблемы существует 2 подхода:

  • Binding стилей через DomSanitizer.bypassSecurityTrustStyle
  • Манипуляция через element.style.setProperty(cssVaribale, value);

nativeElement.style.setProperty

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
  constructor(
    private _elementRef: ElementRef
  ) {}

  onChange(): void {
    this._elementRef.nativeElement.style.setProperty('--background-color', 'black');
    this._elementRef.nativeElement.style.setProperty('--text-color', 'red');
  }
}

На счёт почему используется манипуляция со стилями напрямую this._elementRef.nativeElement.style.setProperty(…) вместо Renderer2 Google Developr Expert ответил:

You no longer have to use renderer to do that in Angular6.

но не объяснил почему так.

DomSanitizer + HostBinding

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
  private _style = '';

  @HostBinding('style') get styleBinding(): SafeStyle {
    return this._sanitizer.bypassSecurityTrustStyle(
      this._style
    );
  }

  constructor(
    private _sanitizer: DomSanitizer
  ) {}

  onChange(): void {
    this._style = ['--background-color: black', '--text-color: red'].join(';');
  }
}

Пример:

Похожие записи

Как добавить ng-bootstrap компоненты в проект Angular-CLI?

Покажу на примере нового проекта.

ng new project_name
cd project_name
npm install --save bootstrap@next
npm install --save @ng-bootstrap/ng-bootstrap

В angular-cli.json в секцию style надо добавить наш CSS, чтобы глобально подключить стили.

  "styles": [
    "styles.css",
    "../node_modules/bootstrap/dist/css/bootstrap.min.css"
  ],
17 августа 2017 г. в Angular

Angular environment variables

Создание и использования переменных окружения в Angular с использованием CLI >= 6 версии.

07 января 2019 г. в Angular

#local variable внутри *ngIf

Представлены 2 варианта решения, как сослаться на локальную переменную шаблона (#myVar) за пределами шаблона:

  • @ViewChild
  • @ViewChildren
12 февраля 2019 г. в Angular

Angular dependency injection

Определение Provider (useClass, useValue, useFactory ), Injector. Декоратор @Inject, ключ multi: true

13 ноября 2018 г. в Angular

Angular Let Directive

*ngIf не отображает содержимое в falsy случаях (0, null, undefined) на async pipe, в пакете @rx-angular/template предлагается решение