How to stop css bleeding in angular 11.2 - css

I am working on a angular 11.2 project and I see that CSS of a component is getting applied to another component which has the same css selector name. How can I stop this? please help

If you apply the styles in Angular #component, it should be applied to that component scope only.
https://angular.io/guide/component-styles
#Component({
selector: 'app-root',
template: `
<h1>Tour of Heroes</h1>
<app-hero-main [hero]="hero"></app-hero-main>
`,
styles: ['h1 { font-weight: normal; }']
})
export class HeroAppComponent {
/* . . . */
}

Use encapsulation in your component declaretion
#Component({
selector:'app-component',
templateUrl:'app.compionent.html',
encapsulation:ViewEncapsulation.None,
})

My solution was to use ViewEncapsulation.None but to use targeted css. ie using specificity. for example if i had a component structure as below:
<div class="parent">
<div class="child">
<span></span>
</div>
</div>
My css would be :
.parent .child > span { ...some css here}
The reason not to use Emulated is that, some lib components can't be targeted with "None" as ViewEncapsulation. hence we need to set it to None and then follow this approach.

Related

Angular 7: Why class style is not applied to DOM component?

I have a component billing that includes ngb-tabset component of Ng Bootstrap.
ngb-tabset has the following DOM element:
<ngb-tabset _ngcontent-c3="" class="content">
<!-- Tabset links-->
<div class="tab-content">
<div _ngcontent-c3="">
<!-- Content -->
</div>
</div>
</ngb-tabset>
<div class="tab-content"> is dynamically displayed according the selected tab.
In my billing.component.scss, the following snippet doesn't work:
.tab-content {
padding-right: 120px;
}
The CSS code is correctly compiled and, normally, seen by navigator but not effect on the item.
But if I apply it on the item outside the component, the code works correctly.
Any idea about this strange behavior?
Method 1 - Set style classes in the tab content template
View encapsulation isolates the CSS styling of each component, preventing the parent component CSS from affecting the child components. The preferred solution in the present case would be to set the style classes in the tab content template definition. Here is an example:
<ngb-tabset>
<ngb-tab title="Simple">
<ng-template ngbTabContent>
<div class="my-style-1">
<p>Some content</p>
</div>
</ng-template>
</ngb-tab>
...
</ngb-tabset>
.my-style-1 {
padding-right: 120px;
color: magenta;
font-style: italic;
}
See this stackblitz for a demo.
Method 2 - Use the ::ng-deep pseudo-class selector
Another method is to use the ::ng-deep shadow-piercing descendant combinator to style the content of the NgbTabset child component:
::ng-deep .tab-content {
padding-right: 120px;
}
See this stackblitz for a demo.
Method 3 - Turn off view encapsulation
Alternatively, you could turn off the view encapsulation of the parent component:
import { Component, ViewEncapsulation } from '#angular/core';
#Component({
...
encapsulation: ViewEncapsulation.None
})
See this stackblitz for a demo.
Angular uses shadow DOM. That means it keeps DOM logics separate from other elements. Components have scoped styles of their own. They are encapsulated in a way that the styles should not effect globally. So, if you want to change ngb-tabset's style you have to come out of its scope. That's why you need to use ViewEncapsulation.None.
In #Component decorator use ViewEncapsulation.None
#Component({
selector: ....,
encapsulation: ViewEncapsulation.None,
styles: [...])}
And, you can use ng-deep also. But you should not use ng-deep because it will be deprecated. See here- https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep

I have a plunker. When I define my css globally, it works. When I define my css in my component, it fails. What's going on?

With reference to this plunker:
https://plnkr.co/edit/GWsbdDWVvBYNMqyxzlLY?p=preview
I have the same css specified in the styles.css file, and in the src/app.ts file.
If I comment in the css in styles.css and comment out the css in src/app.ts, it works.
styles.css:
/* If these are commented in, and the ones in src/app.ts are
* commented out, the three items are spaced appropriately. */
/***
md-toolbar-row {
justify-content: space-between;
}
md-toolbar {
justify-content: space-between;
}
***/
If I comment out the css in styles.css and comment in the css in src/app.ts, it fails.
src/app.ts:
#Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
<md-toolbar color="primary">
<span><md-icon>mood</md-icon></span>
<span>Yay, Material in Angular 2!</span>
<button md-icon-button>
<md-icon>more_vert</md-icon>
</button>
</md-toolbar>
</div>
`,
// If these are commented in, and the ones in style.css are
// commented out, the three items are scrunched together.
/***/
styles: [
`md-toolbar-row {
justify-content: space-between;
}`,
`md-toolbar {
justify-content: space-between;
}`
]
/***/
})
export class App {
name:string;
constructor() {
this.name = `Angular! v${VERSION.full}`
}
}
I'm having trouble visualizing the difference between defining the css for the whole application, and for the specific component. Can someone tell me what's going on?
=================================
#bryan60 and #Steveland83 seem to indicate that the problem lies somewhere in the view encapsulation. And upon further investigation, it does in a sense.
If you look at the code below, you will see that the styles for md-toolbar and md-toolbar-row have an attribute attached. But the html for md-toolbar and md-toolbar-row does not match. Only md-toolbar has the attribute attached. md-toolbar-row doesn't. I have marked the relevant four lines with >>>>>.
So that's the problem but:
1. Do I report it to the material design people as an error?
2. Is there some workaround I can use today?
<html>
<head>
:
<script src="config.js"></script>
<script>
System.import('app')
.catch(console.error.bind(console));
</script>
<link href="https://rawgit.com/angular/material2-builds/master/prebuilt-themes/indigo-pink.css" rel="stylesheet">
<style>
>>>>> md-toolbar-row[_ngcontent-c0] {
justify-content: space-between;
}
</style>
<style>
>>>>> md-toolbar[_ngcontent-c0] {
justify-content: space-between;
}
</style>
<style>
.mat-toolbar {
display: flex;
: :
.mat-mini-fab,
.mat-raised-button {
outline: solid 1px
}
}
</style>
</head>
<body class="mat-app-background">
<my-app _nghost-c0="" ng-version="4.4.0-RC.0">
<div _ngcontent-c0="">
<h2 _ngcontent-c0="">Hello Angular! v4.4.0-RC.0</h2>
>>>>> <md-toolbar _ngcontent-c0="" class="mat-toolbar mat-primary" color="primary" role="toolbar" ng-reflect-color="primary">
<div class="mat-toolbar-layout">
>>>>> <md-toolbar-row class="mat-toolbar-row">
<span _ngcontent-c0=""><md-icon _ngcontent-c0="" class="mat-icon material-icons" role="img" aria-hidden="true">mood</md-icon></span>
<span _ngcontent-c0="">Yay, Material in Angular 2!</span>
<button _ngcontent-c0="" class="mat-icon-button" md-icon-button=""><span class="mat-button-wrapper">
<md-icon _ngcontent-c0="" class="mat-icon material-icons" role="img" aria-hidden="true">more_vert</md-icon>
</span>
<div class="mat-button-ripple mat-ripple mat-button-ripple-round" md-ripple="" ng-reflect-trigger="[object HTMLButtonElement]" ng-reflect-centered="true" ng-reflect-disabled="false"></div>
<div class="mat-button-focus-overlay"></div>
</button>
</md-toolbar-row>
</div>
</md-toolbar>
</div>
</my-app>
</body>
</html>
One of the Angular features is View Encapsulation which basically means that you can define styles scoped only to a specific component without affecting any other components.
By default styles are scoped only for the component they are referenced in, but you can choose to override that to make them available globally by setting your components encapsulation to None.
E.g.
import { Component, ViewEncapsulation } from '#angular/core';
#Component({
selector: 'component-that-shares-styles',
templateUrl: './component-that-shares-styles.component.html',
styleUrls: ['./component-that-shares-styles.component.scss'],
encapsulation: ViewEncapsulation.None // <-- Set encapsulation here
})
*Note that you will need to import ViewEncapsulation from #angular/core
Okay, with help from #Steveland83 and #bryon60, I came to a definite answer. The Material Design people are aware of this problem. They have made a writeup.
https://github.com/angular/material2/blob/master/guides/customizing-component-styles.md
Here's their summary:
Styling other components
If your component has view encapsulation turned on (default), your component styles will only
affect the top level children in your template. HTML elements belonging to child components cannot
be targeted by your component styles unless you do one of the following:
Add the overriding style to you global stylesheet. Scope the selectors so that it only affects
the specific elements you need it to.
Turn view encapsulation off on your component. If you do this, be sure to scope your styles
appropriately, or else you may end up incidentally targeting other components elswhere in your
application.
Use a deprecated shadow-piercing descendant combinator to force styles to apply to all the child
elements. Read more about this deprecated solution in the
Angular documentation.
I don't want to use global css, or a deprecated solution. I guess I will style with classes, and not elements. If someone has a better idea, tell me!

Cannot Understand the Use of :host in components in Angular2

What i have understood of host is that if i have a child component inside a parent component and we want to style a child component from the parent component we can use :host .
and :host-context for vice-versa.
Please let me know if this is the right use of host .
https://angular.io/docs/ts/latest/guide/component-styles.html
When i try to do the same in my App it dosent work
App component template
<div class ="top">
<h1>
Home Component
</h1>
<hr>
<app-ngrx></app-ngrx>
<router-outlet></router-outlet>
<div>
ngrx component template
<h3 class="mine">NGRX</h3>
<button (click)="increment()">Increment</button>
<div>Current Count: {{ counter | async }}</div>
<button (click)="decrement()">Decrement</button>
<button (click)="reset()">Reset Counter</button>
App component CSS
:host(.mine){
color:red;
}
This do not Seem to work Please help i am not able to understand.
I looked at this question But just not able to figure out
Angular 2: How to style host element of the component?
Updated after #Gunter Answer
In my app-ngrx template i have added
<h3 class = "mine">NGRX</h3>
<button (click)="increment()">Increment</button>
<div>Current Count: {{ counter | async }}</div>
<button (click)="decrement()">Decrement</button>
<button (click)="reset()">Reset Counter</button>
and in the app-ngrx css file i have added
:host(.mine){
color:red;
}
But even without adding mine in app component like
<app-ngrx></app-ngrx>
The h3 is red where as i feel it should be red when <app-ngrx class = "mine"></app-ngrx>
What i have understood of host is that if i have a child component
inside a parent component and we want to style a child component from
the parent component we can use :host . and :host-context for
vice-versa
No, this is not what it used for.
:host selector comes from shadow DOM spec.
...This scoped subtree is called a shadow tree. The element it's
attached to is its shadow host.
In angular world, a component's template is a shadow tree. The component's element is a shadow host. So when you're defining styles for :host selector, the styles are applied to the component's element.
:host
In your example, if you defined styles in my-app component, the styles will be applied to <my-app> DOM element. This particular configuration:
:host(.mine){
color:red;
}
Will be applied to the host element that has .mine class:
<my-app class="active">
If you defined styles in app-ngrx component, the styles will be applied to <app-ngrx> DOM element, NOT <my-app>. This particular configuration:
:host(.mine){
color:red;
}
Will be applied to the host element that has .mine class:
<app-ngrx class="active">
:host-context
Now, :host-context is also applied to the host element, but the function (parenthesis) takes a selector that is checked not against the host element itself, but against all ancestors up to document root. If such element is found, the styles are applied.
For example, this selector
:host(.mine){
color:red;
}
matches such structure:
<my-app class="mine">
whereas, this selector:
:host-context(.mine){
color:red;
}
matches this structure:
<div class="mine">
...
<my-app>
This is useful, if you want to apply styles to components view (shadow root) conditionally. This makes h2 always bold:
h2 {
font-weight: bold;
}
whereas this
:host-context(.make-inner-components-bold) h2 {
font-weight: bold;
}
makes them bold only if your component is inside an element with class .make-inner-components-bold.
:host { ... } selects the component itself
:host(.mine) { ... } selects the component itself when it has class="mine" set
:host-context(.mine) { ... } selects the component itself when one of its ancestors has class="mine" set
See also https://angular.io/docs/ts/latest/guide/component-styles.html
#Component({
selector: 'h3',
styles: [':host(.mine) { color: red; }],
template: '<ng-content></ng-content>'})
class MyH3Component{}
<h3 class="mine">this is red</h3>
<h3>this is black</h3>
or with :host-context
#Component({
selector: 'h3',
styles: [':host-context(.mine) { color: red; }],
template: '<ng-content></ng-content>'})
class MyH3Component{}
<body class="mine">
<my-app><my-app>
<body>
AppComponent
template: '<h3>this is red</h3>'
or with class="mine" set
<body>
<my-app><my-app>
<body>
AppComponent
template: '<h3>this is black</h3>'
update
If you want to style the content of a child component (instead of the child component itself) you can use /deep/
:host child /deep/ h3 {
color: red;
}
update 2
::slotted is now supported by all new browsers and can be used with `ViewEncapsulation.ShadowDom
https://developer.mozilla.org/en-US/docs/Web/CSS/::slotted

Is there a way to use css in ng-content inside an Angular2 component?

I tried to include css for children element included in a component via ng-content. It seems to be not implemented yet in Angular 2 or maybe someone has got a solution except to put css in a general stylesheet ?
app.component.ts
<comp-parent>
<comp-child></comp-child>
</comp-parent>
compParent.component.html
<div class="wrapper">
<ng-content></ng-content>
</div>
compParent.component.css
.wrapper > comp-child {
margin-right: 5px; <-- Not applied !!!
}
You can use /deep/ (deprecated) or >>> or ::ng-deep selector:
https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep
E.g.:
.wrapper ::ng-deep comp-child { ... }
Note that >>> seems to not work for projects based on angular-cli.
Apply classes to the html which is going to be rendered.
app.component.ts
<comp-parent>
<comp-child></comp-child>
</comp-parent>
#Component({
selector: 'comp-parent',
template: `
<div class="wrapper">
<ng-content></ng-content>
</div>
`
})
export class CompParent { }
#Component({
selector: 'comp-child',
template: `
<div class="comp-child">
<div>
</div>
</div> `,
})
export class CompChild {}
/// In styles.css
.wrapper .comp-child {
margin-left: 50px;
}
This worked for me in my project.

Styling not applying to child component

I'm trying to apply styling to a child component tag, but I can't do that.
I have child component with anchor tag.
Even though i have styling for anchor tag in the parent component, it's not applying. What's the solution for it?
Working code: http://plnkr.co/edit/CJCpV4ZbG7hdxT2AeSmt?p=preview
Google
In the parent component i'm using the child component and applying styling for this child component.
Html code:
<div class="container">
<div class="test">
<testapp></testapp>
</div>
</div>
Css code:
.container{
font-family:sans-serif;
font-size:18px;
border: 1px solid black;
}
.test{
width:50%;
background-color:#f0f5f5;
}
.container:hover .test{
background-color:#e6ffe6;
}
.container:hover .test:hover{
background-color:#ffffe6;
}
.container .test a {
color: red ;
}
.container .test a:hover {
color:green;
}
It's because by default components have view encapsulation (shadow dom). To disable this behavior, you can leverage the encapsulation attribute, as described below:
import {Component, ViewEncapsulation} from '#angular/core';
import {TestApp} from 'testapp.component.ts';
#Component({
selector:'test-component',
styleUrls: ['test.component.css'],
templateUrl: './test.component.html',
directives:[TestApp],
encapsulation: ViewEncapsulation.None // <------
})
export class TestComponent{
}
See this plunkr: http://plnkr.co/edit/qkhkfxPjgKus4WM9j9qg?p=preview.
When using the styleUrls property, the styles are local to the one component, not to its children. So I made two changes:
1) Moved the styleUrls to the testapp component.
2) Moved the div to the testapp component.
import {Component} from '#angular/core';
#Component({
selector:'testapp',
styleUrls: ['./test.component.css'],
template: `
<div class="test">
Google
</div>
`
})
export class TestApp{
}
EDITED: This should solve:
In the css of child class write below code
:host.parentclass childclass{
}
The parentclass is immediate parent of child. childclass is the class applied to child component.

Resources