Control CSS Variable from Angular 5

Control CSS variable from Angular 5

Yes you can set variables in root scope:

:root {
--main-color: red
}

Yes you can use :host selector to target element in which the component is hosted.

:host {
display: block;
border: 1px solid black;
}

You can also use, :host-context to target any ancestor of the component. The :host-context() selector looks for a CSS class in any ancestor of the component host element, up to the document root.

:host-context(.theme-light) h2 {
background-color: #eef;
}

Note: ::ng-deep or /deep/ or >>> has been deprecated.

Read more about it here: special css selectors in angular

Just an additional information.
It works both inside ':root' as well as ':host'
We can set values to them by:

constructor(private elementRef: ElementRef) { }
then
this.elementRef.nativeElement.style.setProperty('--color', 'red');

Change css variables dynamically in angular

You can update them using

 document.documentElement.style.setProperty('--theme-color-1', '#fff');

If u want to update many values, then create a object

 this.styles = [
{ name: 'primary-dark-5', value: "#111" },
{ name: 'primary-dark-7_5', value: "#fff" },
];

this.styles.forEach(data => {
document.documentElement.style.setProperty(`--${data.name}`, data.value);
});

The main thing here is document.documentElement.style.setProperty. This line allows you to access the root element (HTML tag) and assigns/overrides the style values.

Note that the names of the variables should match at both places(css and js files)


if you don't want to use document API, then you can use inline styles on HTML tag directly

    const styleObject = {};

this.styles.forEach(data => {
styleObject[`--${data.name}`] = data.value;
});

Then In your template file using ngStyle (https://angular.io/api/common/NgStyle)

Set a collection of style values using an expression that returns
key-value pairs.

<some-element [ngStyle]="objExp">...</some-element>
<html [ngStyle]="styleObject" >...</html>  //not sure about quotes syntax

Above methods do the same thing, "Update root element values" but in a different way.

When you used :root, the styles automatically got attached to HTML tag

Generate dynamic css based on variables angular

Direct approach available in angular is using ngstyle as follows

<div [ngStyle]="{'color': style.colorVal ? style.colorVal : '#000', 'font-size' : style.fontSize ? style.fontSize : '16px' }"></div>

After going through different methods and approached to add dynamic css to all pages on angular app I ended up with following solutions.

Requirement : generate dynamic css based on values returned from and API to change design and styling.

Solution :

  1. create a new component and create a service to load dynamic css variables from API.
  2. Add style tag in template file and use variable values for properties.
  3. Load this template on all pages or on main template.
  4. On app build style will be moved to head tag.

Code sample

import { CssService} from './Css.service';

@Component({
selector: 'DynamicCss',
templateUrl: './DynamicCss.component.html',
styleUrls: ['./DynamicCss.component.scss']
})
export class ServiceProviderComponent implements OnInit {
cssVariables: any;
constructor(private cssService:CssService){
/* call the service/api to get the css variable values in cssVariables */

}
}

Now apply css using jquery or javascript to append css with help of function like following

appendCss(customData)
{
let text = '.custom-form-1 {
background-image: url("`+customData.background_image+`");
}';
$(document).ready(function(){
$("style").append(text);
});
}

and call this function after loading custom data from service or other variable like I did it ngOnInit

ngOnInit(){
this.appendCss(this.customizeFormData);
}

Its using jquery but can be done with javascript/typescript as well if you dont want to use jquery in your angular app

Other useful resource https://github.com/angular/angular/issues/9343#issuecomment-312035896

Change the values of CSS variables at runtime in Typescript

Since these values are defined at root level, you can just update them using document. I am not exactly sure on how you can access the document in angular, but once you have document, you can do something like this:

document.documentElement.style.setProperty(`--${your-variable}`, value + suffix); //suffix may be px or ''

This way, you will directly set the css variable which will take effect at all the places and you will not have to target individual elements.

Angular 5: How to define color pallet in a central file

A nice and modern way, would be to use css variables. Global support is pretty good, and it has been recommended by the angular community.

import { Component, Renderer2 } from '@angular/core';

@Component({
selector: 'my-app',
template: `
<h1> Hello </h1>
<h2> World </h2>
`,
styles: [
'h1 { color: var(--primary); }',
'h2 { color: var(--accent); }'
]
})
export class AppComponent {

constructor() { }

ngOnInit() {
const colors = new Map([
['primary', 'blue'],
['accent', 'red'],
])

Array.from(colors.entries()).forEach(([name, value]) => {
document.body.style.setProperty(`--${name}`, value);
})

}
}

Live demo

Angular: Use Renderer 2 to Add CSS Variable

Angular sanitizes CSS variables set in property bindings. You can bypass this behavior with DomSanitizer.

@Component({
selector: 'my-app',
template: `
<button (click)="dec()">-</button>
<button (click)="inc()">+</button>

<div [style]="style"> My height is set by CSS Variable </div>
`,
styles: [`
div {
height: var(--height);
}
`
]
})
export class AppComponent {
height = 50;

get style() {
return this.sanitizer.bypassSecurityTrustStyle(`--height: ${this.height}px`);
}

constructor(private sanitizer: DomSanitizer) { }

inc() {
this.height += 10;
}

dec() {
this.height -= 10;
if (this.height <= 0) {
this.height = 0;
}
}
}

Live demo

You might find this article interesting. It goes into details on theming Angular components with CSS variables.



Related Topics



Leave a reply



Submit