Angular : CSS of one component is conflicting with another Component. - css

My project Hierarchy is as below:
Component_HomePage
|
|---> Component_Tool1
| |
| ---> Component_Inner_01
|
|---> Component_Tool2
|
---> Component_Inner_02
Obviously all Component are having different styling.
Though there are some CSS classes in Component_Inner_01 & Component_Inner_02 whose names are same but content is different.
For example:
Component_Inner_01.CSS having list-group-item class
.list-group-item{
padding: 0px;
}
And Component_Inner_02.CSS is also having list-group-item but content is diff.
.list-group-item{
padding: 10px;
}
So for the first time when i browse Component_Inner_01 list-group-item takes padding as 0px, which is perfect.
But when i view Component_Inner_01 page after viewing Component_Inner_02 page, list-group-item class of Component_Inner_01 is taking padding as 10px.
I figured out the issue was in Component_Inner_02
Component_Inner_02's decorator having metadata encapsulation which is set to ViewEncapsulation.None
But i don't know what making CSS classes conflict with each other when having encapsulation: ViewEncapsulation.None, Can anybody explain ?

View encapsulation means that your view is encapsulated : it means Angular adds random attributes to your tags to distinct them from one to another.
If you use encapsulation: ViewEncapsulation.None, then your view isn't encapsulated anymore : styles don't have random attributes, and start conflicting.
If you want to stop that, remove that line from your component.
the CLI provides a global style sheet called style.[extension] where you can put all global styles. You don't need to deactivate encapsulation.

Instead of removing the line as #trichetriche said use the necessary encapsulation mechanism.
FYI
ViewEncapsulation.Emulated: Any styles we define on a component don’t leak out to the rest of the application.
But, the component still inherits global styles like twitter bootstrap.
ViewEncapsulation.Native: Styles we set on a component do not leak outside of the components scope.
Component is also isolated from the global styles we’ve defined for our application.
ViewEncapsulation.None: We are not encapsulating anything,
the style we defined in our component has leaked out and started affecting the other components.

You can make a wrapper element and give it an Id, use that ID to give styles for that particular component. And same for the second component also. So that the styles won't make conflict one after another.
<div id="component1">
//Component1 code here
</div>
<div id="component2">
//Component2 code here
</div>
Styles
#component1 .list-group-item {
padding: 0px;
}
#component2 .list-group-item {
padding: 10px;
}

Related

Make Angular component stylesheet work with sub-components

I'm relatively new to Angular, and I have a doubt about component stylesheets.
I have an Angular 12 app and created a component named my-component. The template of the component in question is something like this:
my-component.html
<div>
...some html...
<some-other-angular-component></some-other-angular-component>
...some other html...
</div>
some-other-angular-component is another component, either from the app itself or a third party library.
Now, what I want to do in my-component is apply some CSS rules to the contents of some-other-angular-component. I know that the HTML it generates contains classes that I can target, so I tried to add this to my component CSS:
my-component.scss
.some-other-angular-component-inner-class {
background-color: red;
}
However, this doesn't work, it appears that the component's CSS file only applies rules to the HTML defined directly in the component's template, not the HTML generated by sub-components.
Is there a way to make this work? I find myself having to add my CSS to the webapp's main style.scss file, even when I want to apply the rule only to the particular some-other-angular-component instance inside of my-component. It makes styling confusing and needlessly fragmented. Is this intended, or what am I missing?
I think you may want to look into View Encapsulation.
#Component({
selector: 'app-no-encapsulation',
template: `
<h2>None</h2>
<div class="none-message">No encapsulation</div>
`,
styles: ['h2, .none-message { color: red; }'],
encapsulation: ViewEncapsulation.None,
})
export class NoEncapsulationComponent { }
These styles will be added to head and will be applicable to other components as well if style rule matches.
Please note, with this you are only enabling this behaviour for just this component. Chances of overlapping CSS rules is still there but is lot less in comparison to directly putting styles in style.css.
I will also suggest that you add .class or #id attribute in mark up to ensure that your rules don't overlap by default.
For example:
.my-component .rule-one {
}
It will ensure that my rules are only applied are on component that has this class applied on it.

PrimeNg p-inputnumber cannot be styled

I am getting stuck trying to implement the PrimeNg Inputnumber element: https://www.primefaces.org/primeng/showcase/#/inputnumber
As per its documentation, there are a couple of attributes that can be used to style the input element, most notably styleClass and inputStyleClass. Unfortunately, neither of them work but rather they get completely ignored.
component.html:
<p-inputNumber
inputStyleClass="form-control-inputnumber" [(ngModel)]="subwinFld.orderAdd.doubleVal">
</p-inputNumber>
Global styles.css
.form-control-inputnumber {
background:red;
width: 100%;
}
I have used and successfully styled other primeNg elements before, using the exact same strategy, for example the p-calendar element. However, here it completely ignores the attribute.
What am I doing wrong?
Try to add :host ::ng-deep
Style are scoped, and there are not inherited by nesting.
:host ::ng-deep .form-control-inputnumber {
background:red;
width: 100%;
}
styleClass is the property that put the class on the first level of a PrimeNG Component.
inputStyleClass is the property that will put the class on the input itself for this specific component.
I often have to play with the style encapsulation with styleClass, so I believe it is the same for inputStyleClass
Word about ::ng-deep deprecation
Yes, for sure it is deprecated. To be totally fair, there is an alternative. But the alternative counterpart is huge and in my opinion, the big picture is worst.
You can make it work by changing your ViewEncapsulation in your component with :
encapsulation: ViewEncapsulation.None
as follow
#Component({
selector: '',
template: '',
styles: [''],
encapsulation: ViewEncapsulation.None // Use to disable CSS Encapsulation for this component
})
Reference 1 about alternatives and reasons of deprecation
Reference 2 about alternatives of ::ng-deep
The choice is yours, but for my part I continue to use this methodology with third party library like primeNG, because there is no real alternative.
You either choose to make your style global or your style scoped.
Kill the encapsulation for the sake of a third party library usage, seems to me an overkill process.
By making your ViewEncapsulation to none, you give up on style encapsulation, so beware of it.
HTML:
<p-inputNumber styleClass="input-styling"></p-inputNumber>
CSS:
::ng-deep .input-styling input {
width: 20px !important;
}
The cause for the missing styling was a runtime error in the typescript of the component, that prevented the correct compilation of the DOM.
I assumed that did not matter, since they should not be related at all, but they are (somehow). Since others may have the same erroneous assumption, I am leaving this question here, rather than deleting it.
Simply add
styleClass="w-full" to p-inputNumber tag to adjust 100% width or according style to reach desired width in reference to https://www.primefaces.org/primeflex/width
No encapsulation: ViewEncapsulation.None is needed and no extra css classes/styling is required.

Angular - How To Organize CSS Overrides Across Components For The App

I'm relatively new to angular. In the process of converting a React app to Angular just for learning purposes. I have a parent component that has a button (Custom Button Component). This button when loaded in the parent should be hidden and on hover should show the button. So you probably get an idea that I have some CSS selectors related to the parent component that override the child CSS. First should be display: none and then on hover I change it to display: flex
So the first problem I encountered was that I could not override the child CSS from the parent CSS. After reading all kinds of posts I moved the CSS overrides from the parent CSS to the global stylesheet and also added encapsulation: ViewEncapsulation.None to the child component.
Next thing I noticed is that the align-items: center was not working on the child. First thought I had that guess I have to add that part to the global styles also? but what I really need to know is that is this the norm in Angular? If yes, then some things don't make sense to me. These styles are really not global. They are only related to the parent component then it seems kind of weird to add those to the global stylesheet.
In regards to the align-items not aligning the child (custom-button), I believe that happens because of the extra div being added around the button. So how do you handle such situations?
Appreciate any advice/tips.
Thank you!
You can overwrite children CSS classes from the parent componet. this is the way:
Assuming your child component have this CSS
.child-class {
background-color: blue;
}
When you use this component the background color will be blue. But if you want to change that color to RED. In the parent component where you want the change you need to do this:
In your parent component
:host {
::ng-deep{
.child-class {
background-color: red;
}
}
}
:host this refers to the component's HTML tag (that is created by Angular, in your case the tag of the component that contains the app-custom-button). Also you can apply css to the component tag.
for example:
:host{
width: 100vw;
height: 100vh
}
And with ::ng-deep you can overwrite ALL styles inside your compoent. Does not matter if is a style from your child compoenent, grandchild, great-great-grandson, etc... even if its a component from an external library.
So... For example you can have the "custom background color as blue" then in one component you can keep that color but in other component you can change the color to red and in other component you can change the color to green....
Angular have the concept of ViewEncapsulation. By default, the value is set to ViewEncapsulation.Emulated and the css you put in the component is specific to the component and only to this component. The CSS will not be applied to the child components.
You can switch to ViewEncapsulation.None and you will disable this behavior and all the css rules in your css file will be applied to all your components in the application, and maybe you don't want this behavior. That's why I advice you to leave this option.
The other option you got is to put your specific css rule in src/style.css (if you didn't modify the default path). All css rules put in this file will be applied for all the application and you can keep the ViewEncapsulation of your component.
For align-items, i think you are right : the app-custom-button is wrapping your button, so you need to set a width: 100% to your button, then eventualy resize your app-custom-button

Override Angular Material CSS differently in different components

I have two components with tab groups in them. One is a main page and I have overwritten the css to make the labels larger, done using ViewEncapsulation.None. The other is a dialog, and I want to keep it small but still apply some other custom styles to it.
When I open the dialog after visiting the other tabs page, it copies all the styles, which I have figured is because ViewEncapsulation.None bleeds CSS but not exactly as expected.
Is there anyway to override Angular Material styles without changing ViewEncapsulation so that I can keep the two components separate?
Solution 1: you can put all elements of your component into a parent element with a css class and override the material style into it.(it's custom capsulation)
Note: ViewEncapsulation is none here.
component.html
<div class="my-component__container">
<!-- other elements(material) are here -->
</div>
component.scss
.my-component__container{
// override material styles here
.mat-form-field{...}
}
Solution 2: use /deep/(deprecated).(use ::ng-depp insteaded)
:host /deep/ .mat-form-field {
text-align: left !important;
}
Solution 3: don't change ViewEncapsulation , then:
:host {
.my-component__container{}
}
if you would like to customise your Angular material components and provide your own stylings, I have the following suggestions. You may use one of them.
1) Overwrite the classes on your main style.css (or style.scss, whichever you are using). If you are wondering, it is the one that is on the same directory level as your index.html, main.ts, package.json, etc. You might need to add the !important declaration.
For instance,
.mat-form-field-label {
color:blue!important;
}
2) Customising the various Angular Material directive (such as MatPlaceholder) by providing a custom class.
For instance, when we use the MatPlaceHolder, and on the component.html template,
<mat-placeholder class="placeholder">Search</mat-placeholder>
On your component.css, we can then supply the css properties to the placehodler class
.placeholder {
color: green
}
Note:
Alternatively you may use ::ng-deep, but I would strongly suggest using ::ng-deep as it will soon be deprecated.
::ng-deep .mat-dialog {
/* styles here */
/* try not to use ::ng-deep */
}
You can use ::ng-deep. Refer NgDeep

Overriding the encapsulated CSS of external component

I was wondering how to override the encapsulated CSS of an external component.
So I am using material2 in my project and the tabs component has a the attribute overflow set on tab-body. Is it possible to override the overflow value?
You can use the special css /deep/ instruction. See the documentation
So, if you have
app
sub-component
target-component
<div class="target-class">...</div>
You can put in your apps css (or less):
/deep/ .target-class {
width: 20px;
background: #ff0000;
}
Obviously, you can put this css fragment in sub-component as well.
From this article
Although the style of a component is well isolated, it can still be easily overridden if necessary. For that, we just need to add an attribute to the body of the page:
<body override>
<app></app>
</body>
The name of the attribute can be anything. No value is needed and the name override makes it apparent what its being used for. To override component styles, we can then do the following:
[override] hello-world h1 {
color:red;
}
Where override is the attribute, hello-world is the target component, and h1 is whatever you are trying to restyle. (get this right or it wont work).
Your component hello-world would be
selector: 'hello-world',
styles: [`
h1 {
color: blue;
}
`],
template: ` <h1>Hello world</h1> `
I think this is the most elegant way.
Alternatively if you are building a library of some sort, you can reset the styling altogether by doing something fancy in your css like:
:host-context(.custom-styles) {
//.. css here will only apply when there is a css class custom-styles in any parent elem
}
So then to use your component you'd use
<hello-world class="custom-styles">
But this is way less convenient than the first option.
::ng-deep .tag-or-css-class-you-want-to-override {
/* Add your custom css property value. */
}
The syntax ::ng-deep is used to override outside css class or tags without using ViewEncapsulation.None.
I see variations of this question a lot and since this is the top question on the subject I want to give the simplest answer. ng-deep and similar functionality is deprecated, so it's best to just rely on vanilla CSS.
Simply create a CSS selector with a higher specificity.
Most people (including myself) get hung up trying to do that because they don't understand two things:
Angular View Encapsulation
CSS Specificity
Angular View Encapsulation
View Encapsulation ensures CSS within a component only affects that component. To affect other components, you need some global CSS. You can do this by using a global style file like styles.css or by disabling View Encapsulation on a component.
#Component({
...
encapsulation: ViewEncapsulation.None
})
CSS Specificity
When two selectors select the same element, the CSS that actually gets applied is based on specificity: https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity
You can increase specificity by simply adding more elements to your CSS selector. For example p.className is more specific than just .className. If you're lazy, you can just repeat a class name to increase specificity. .className.className is more specific than .className.
So to override any CSS in an Angular project, go into styles.css and repeat the class selector until your CSS has a higher specificity than the original.
.className.className.className {
color: red;
}
Didn't work? Add another .className.
Just check the class that is being applied to the tabs by the external component (use Inspector or any other tool). In your style css file, add the same name of the class for the tabs and set the overflow property along with adding !important to it to make sure it overwrites the previous one. Also make sure your css link to the page is added after the external component css link if any.
Hope this helps.
::ng-deep .css-class-you-want-to-override{
/*your custom css property value. like below */
background: white !important;
}

Resources