59

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.

Vivendi
  • 20,047
  • 25
  • 121
  • 196
  • 2
    This is just my personal opinion, but why don't you just add a logued-in class to the body or something like that and add css styles specific to that class override the regular ones, this feels more cascade than overriding the styles inside each component. – Langley Jan 19 '16 at 16:25

12 Answers12

106

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,
  ...
})
Sasxa
  • 40,334
  • 16
  • 88
  • 102
  • 5
    This worked for me and is a much better way then the one marked as answer. Thanks. – Roet Mar 25 '16 at 07:46
  • 3
    Thanks for this! This should be the accepted answer. – hartz89 May 20 '16 at 17:29
  • 20
    Correct me if I'm wrong, but this wouldn't allow changing global (body tab) styles per component though would it? This would just add the css to the app and it would always be there, even when a different component is loaded. – TehOne Jul 25 '16 at 07:35
  • 1
    so using this, how would you toggle body's `padding-top` to say 120px when some component variable like `showCustomContent` is true? – user1354934 Sep 20 '16 at 20:02
  • 3
    @Sasxa, what about if there are children component that we want dont'be affect for these global styles? – stackdave Dec 14 '16 at 22:46
  • 2
    This changes the value for all components. This is not at all what the original requester was asking for. (He asked for an override, not a change to the property.) – jfgrissom May 29 '17 at 03:57
  • This is the best answer! – Armeen Moon Jun 15 '17 at 04:08
  • 1
    Hey! this works,BUT this MESSES the whole style of my app: i have the following: login component admin component and when i enter to admin, i have to rewrite the styles from login. and when i press the back button on the browser, the styles of admin are being carried to login. Because of what @TehOne said. I think this isn't the real solution to the problem and it's a bad practice becaues it is just putting some style above everything... I mean, there must be another way to do this! – kevinrodriguez-io Jul 13 '17 at 20:55
  • Not sure if this has changed, but I ran a test with two components in the same module. One with native and one without encapsulation same CSS. The CSS from the other item is not bleeding over (unless it only matters for children)? – user521990 Jul 07 '20 at 19:52
37

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.

jfgrissom
  • 592
  • 5
  • 13
25

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.

21

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');

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • seems like the body-selector is not allowed (anymore), quoting yourself (https://stackoverflow.com/questions/41249161/how-to-change-class-of-body-in-angular2typescript-project) So the third solution you suggest here is the only possible one? – simne7 Nov 29 '17 at 14:07
  • thx for the example.. my linter nevertheless tells me that using the 'body' selector isn't correct (however the app builds). http://codelyzer.com/rules/component-selector/ refers to some angular guidelines. Hm, going to live with a linter error in this case I think. – simne7 Nov 29 '17 at 14:25
10

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

Omer
  • 139
  • 1
  • 5
  • 1
    but conditionaly? – Ben Taliadoros Feb 27 '18 at 11:21
  • @BenTaliadoros Please explain what do you mean by conditionally? style conditions are usually written inside a [ngClass] or [ngStyle]. But I have the feeling you talk about something else. – Omer Mar 12 '18 at 13:43
  • Sorry, i meant how you you conditionally add a style to the body, [ngClass] won't work on the body tag unless the root component includes the body tag – Ben Taliadoros Mar 12 '18 at 14:33
  • @BenTaliadoros I guess the only possible way is with js, and inject the data back to the html/css. Can you specify what do you want to do? – Omer Mar 15 '18 at 07:44
  • so i had an overlay which places a class on the body element, but my angular app is bootstrap within the body. I smiply use js to target the body, but it feel a little un-angular and hoped there would be a better way – Ben Taliadoros Mar 15 '18 at 09:30
  • This would be more appropriate as a comment not an answer. – coderfin Sep 14 '20 at 17:05
3

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.

Vamshi
  • 9,194
  • 4
  • 38
  • 54
3

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');
      }
Anton Pegov
  • 1,413
  • 2
  • 20
  • 33
2

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')
}
DINESH Adhikari
  • 1,242
  • 1
  • 12
  • 11
2

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"] 
            } 
        } 
    } 
}
Kris
  • 21
  • 2
1

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.

Chaitanya Chauhan
  • 743
  • 1
  • 11
  • 28
0

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.

Eoin
  • 163
  • 1
  • 9
0
::ng-deep{
    html, body{
        //something here
    }
}
Hoopou
  • 13
  • 1
  • 6
  • 1
    Your answer could be improved by adding more information on what the code does and how it helps the OP. – Tyler2P Oct 08 '22 at 08:38