Style html,body from web component (Angular 2)

AngularShadow Dom

Angular Problem Overview


I'm working on a LoginComponent in Angular 2 that should "restyle" the html and body tags, so I can put in a background image specific for the login page.

But just adding a style for the html, body in my login.css doesn't seem to work.

Is there a way to override the style on the html, body from a component? Or any element for that matter.

I've tried things like:

:host(.btn) { ... }
:host(.btn:host) { ... }
.btn:host { ... }

to style an element from outside the Login component. But nothing seems to work.

Angular Solutions


Solution 1 - Angular

You need to change the way your component serves css using ViewEncapsulation. By default it's set to Emulated and angular will > add an attribute containing surrogate id and pre-process the style rules

To change this behavior import ViewEncapsulation from 'angular2/core' and use it in component's metadata:

@Component({
  ...
  encapsulation: ViewEncapsulation.None,
  ...
})

Solution 2 - Angular

I'm not sure if this is exactly what you're looking for but this won't leave you with a permanently changed body background-image.

Here is how I did it for something similar. If tou want to impact the body background image for just this page this may work. (I've not tested this fully but it seems to work on windows browsers.)

Inside your component you can just work directly through the DOM when the component gets constructed. When it gets destroyed you can undo the change.

export class SpecialBackground  {
  constructor(){
    document.body.style.backgroundImage = "url('path/to/your/image.jpg')";
    document.body.style.backgroundPosition = "center center";
    document.body.style.backgroundRepeat = "no-repeat";
    document.body.style.backgroundAttachment = "fixed";
    document.body.style.backgroundSize = "cover";
  }
  ngOnDestroy(){
    document.body.style.backgroundImage = "none";
  }
}

For your purposes you can use a different function (rather than the constructor) when you button is clicked and you should good to go.

Solution 3 - Angular

The way I used it is

constructor() {
    document.body.className = "bg-gradient";
  }

ngOnDestroy(){
    document.body.className="";
  }

This will dynamically add and remove style from the body for a particular component.

Solution 4 - Angular

You could try

body {
  /* body styles here */
} 

but styles in components are not supposed to be applied to elements outside themselves.

Another way is to use body as selector in your main component and use host-binding to set/remove a CSS class on body to make CSS you added to your index.html match.

@Component({
  selector: "body", 
  host: {
    "[class.some-class]":"someClass" 
  }, 
}) 
export class AppComponent {
  constructor(private loginService: LoginService) {
    loginService.isLoggedInChanged.subscribe((value) => {
      this.someClass = value;
    });
  }
  someClass: bool = false;
} 

when you set someclass to true (usind some binding to a service, the class gets added to the body.

If you don't want to add CSS globally you can also bind to a style attribute directly

@Component({
  selector: "body", 
  host: {
    "[style.background-image]":"bodyBackgroundImage()" 
  }, 
}) 
export class AppComponent {
  bool isLoggedIn = false;
  constructor(private loginService: LoginService) {
    loginService.isLoggedInChanged.subscribe((value) => {
      this.isLoggedIn = value;
    });
  }
  function bodyBackgroundImage() {
    return this.isLoggedIn ? 'url("gradient_bg.png")': 'none';
  }
} 

update

DomAdapter is gone. Renderer2 should provide similar functionality.

A way to style <body> directly from the login component is to use the DomAdapter (see also https://github.com/angular/angular/issues/4942)

System.import('angular2/src/platform/browser/browser_adapter').then(function(browser_adapter) {
  browser_adapter.BrowserDomAdapter.makeCurrent();
})
...
_dom: DomAdapter = new BrowserDomAdapter();
_dom.setStyle(_dom.query('body'), 'padding', '50px');

Solution 5 - Angular

I just edited the styles.scss file and it worked for me.

Solution 6 - Angular

I had same issue with margin-top , the way I fixed is

constructor(
    private _renderer: Renderer2,
) {
    this._renderer.removeStyle(document.body, 'margin-top');
}

This worked perfectly for me.

Solution 7 - Angular

I use this approach in my component, loaded in router-outlet:

      ngOnInit() {
        // Change <body> styling
        document.body.classList.add('align-content-between');
      }

      ngOnDestroy() {
        // Change <body> styling
        document.body.classList.remove('align-content-between');
      }

Solution 8 - Angular

Better to add css file at root level and configure it in angular-cli.json OR add it in index.html . so you can write your reset and global styles and no need to worry about shadow dom and other concepts.

Solution 9 - Angular

Very simple try this

//Add Style
document.body.style.overflow = 'hidden'

// Remove style
document.body.style.removeProperty('overflow')

//Remove style on destroy
ngOnDestroy(): void {
  document.body.style.removeProperty('overflow')
}

Solution 10 - Angular

As an additional update, when using Angular: 9.1.12, adding styling to the body tag can be accomplished by using the src/styles.css file.This is assuming the src/angular.json's projects' architect object's styles array has been set to src/styles.css.

The angular.json file should look similar to below when configuring a global style sheet such as: src/styles.css. There are more details located within the angular documentation as well: https://angular.io/guide/workspace-config#style-script-config

{ 
	"projects": { 
		"app": { 
			"architect": { 
				"styles": ["src/styles.css"] 
			} 
		} 
	} 
}

Solution 11 - Angular

Put your styles into a css class/ classes and do something like this in your component:

constructor() {
    document.body.classList.add("mainMapPageBody");
  }

ngOnDestroy(){
    document.body.classList.remove("mainMapPageBody");
}

This prevents you from having to write out lots of adding and removing of styling in the constructor/ destructor, making for easier debugging as in other answers.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionVivendiView Question on Stackoverflow
Solution 1 - AngularSasxaView Answer on Stackoverflow
Solution 2 - AngularjfgrissomView Answer on Stackoverflow
Solution 3 - AngularAkash BavaleView Answer on Stackoverflow
Solution 4 - AngularGünter ZöchbauerView Answer on Stackoverflow
Solution 5 - AngularOmerView Answer on Stackoverflow
Solution 6 - AngularVamshiView Answer on Stackoverflow
Solution 7 - AngularAnton PegovView Answer on Stackoverflow
Solution 8 - AngularChaitanya ChauhanView Answer on Stackoverflow
Solution 9 - AngularDINESH AdhikariView Answer on Stackoverflow
Solution 10 - AngularKrisView Answer on Stackoverflow
Solution 11 - AngularEoinView Answer on Stackoverflow