Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2's component's styles are not inherited in the encapsulated child component

Tags:

angular

I am writing two components - ComponentA and ComponentB, where ComponentA encapsulates ComponentB. Both of them have a p tag. In my ComponentA, I am writing styles: p { color:red } inside my @Component decorator. The ComponentA's p is changed to red but ComponentB's color remains black.

I think it's a bug which needs to be resolved.

like image 902
Vineet 'DEVIN' Dev Avatar asked Apr 20 '16 09:04

Vineet 'DEVIN' Dev


3 Answers

Style encapsulation (preventing style from bleeding into or out of components) is a main feature of Angular components.

There are different options to achieve what you want

@Component({
  selector: 'component-b',
  styles: [`
    p { color: red; }
  `]
  ...
  encapsulation: ViewEncapsulation.None
})

or you can change the CSS selector to cross component boundaries with the recently introduced (Angular2 only) shadow piercing CSS combinator >>>

@Component({
  selector: 'component-b',
  styles: [`
    :host ::ng-deep p { color: red; }
  `]
  ...
})

The 2nd approach works with the default encapsulation (ViewEncapsulation.Emulated).
You can't use ::ng-deep (>>>) with encapsulation: ViewEncapsulation.Native.
Support for >>> (or the equivalent /deep/) was removed from Chrome and never really supported in other browsers.

hint:
/deep/ seems to work better with SASS than >>>
SASS introduced ::ng-deep a while back to support this Angular feature (when support for /deep/ was removed from SASS)

like image 169
Günter Zöchbauer Avatar answered Nov 11 '22 19:11

Günter Zöchbauer


As mentioned in the accepted answer: this is not a bug.

That said, here are two alternatives to inheriting parent styles:

@Component({ styleUrls })

Adding the parent component style sheet to the list of styleUrls:

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

@Component({
  selector: 'app-child-component',
  templateUrl: './child.component.html',
  styleUrls: ['../parent.component.css', './child.component.css']
//             ^^ Going up
})

export class AppChildComponent implements OnInit {
  constructor() { }
  ngOnInit() { }
}

Preprocessor Imports (SCSS, SASS, LESS)

You can also import parent styles using preprocessors. You'll just need to adjust your project settings to use them:

@import "../parent.component.sass"
// .app-parent-component
//   border: 1px solid red

.app-child-component
  border: 1px solid blue

Compiled Output

Both will generate the classes with the right scope so you'll have effectively inherited the parent styles.

/* Compiled CSS */
.app-parent-component[_ngcontent-c1=""] {
  border: 1px solid red; }

/* Redeclares parent styles but with the child's scope */
.app-parent-component[_ngcontent-c2=""] {
  border: 1px solid red; }
.app-child-component[_ngcontent-c2=""] {
  border: 1px solid blue; }
like image 32
Enom Avatar answered Nov 11 '22 20:11

Enom


It is not a bug.

Component styles normally apply only to the HTML in the component's own template -- reference

If you want styles that you define in a parent component to affect ancestor components, I would use the use the /deep/ selector (which has the alias >>> as Günter used in his answer) in the parent component, which will force the style down through all ancestor components. Note that this will apply the style to all view children as well as content children.

@Component({
  selector: 'component-a',
  styles: [`/deep/ p { color: red; }`]
})

Plunker

See also the Special Selectors section in the Component Styles dev guide.

like image 24
Mark Rajcok Avatar answered Nov 11 '22 20:11

Mark Rajcok