I'm leaning Angular by following Udemy course and I have this style:
server dl {
display: flex;
}
and server component and it don't work. The style is not applied to html. Because generated style look like this:
server[_ngcontent-c1] dl[_ngcontent-c1] {
display: flex;
}
and DOM look like this:
<server _ngcontent-c0="" _nghost-c1="">
<dl _ngcontent-c1="">
<dt _ngcontent-c1="">Plantform</dt>
<dd _ngcontent-c1="">Linux x86_64</dd>
</dl>
</server>
_ngcontent-c0 instead of _ngcontent-c1, why this is happening? Why the style don't match the DOM?
I'm using Angular app using generated by CLI with Less (but I've created component by hand using server as selector, the same happen if name is app-server).
Why this attribute selectors are added? What about if I use this component in different place? I want to match all elements inside component that's why I've added server as selector to always match all inside this component.
How can I use component name that is added to html as root for my whole style? Or is this not good practice in Angular and this is handled other way, if so can someone explain?
Every element of a component is scoped-automagically / polyfilled by angular (in accordance with css spec for scoping) using those attributes you noticed. So basically, you don't have to write component-name element when you write css for that component but you can just write:
dl {
display: flex
}
Angular will make sure that this style is only applied to dl inside server by using the generated attributes, it is essentially a polyfill for css scoping. If all your targeted browsers support css scoping natively, you can even set ViewEnacpsulation.Native
In some cases where you decide to style the root element, you have to use the special selector :host
The :host selector is the only way to target the host element. You
can't reach the host element from inside the component with other
selectors because it's not part of the component's own template. The
host element is in a parent component's template.
So instead of writing server {background: red} you will write :host {background: red}
This is also inline with css spec for scoping.
Read more about CSS coping and component based CSS to know more about this strategy.
As a primer read the base documentation in Angular
Also, note that you can add your css to any global stylesheet like the way you did:
server dl {
display: flex
}
Which way to go largely depends on how you plan to manage and scale css.
You can use at .TS file below the class.
This is delete all this _ngcontent
#Component
selector,
template,
styles,
This code encapsulation: ViewEncapsulation.None
Related
When creating Web Components with encapsulated styles using Shadow DOM, parts of the shadowed markup can be styled using the ::part pseudo selector (https://developer.mozilla.org/en-US/docs/Web/CSS/::part).
Can the part selector be used to target nested shadow parts?
<custom-element>
#shadow-root
<div part="thats-easy"></div>
<another-custom-element part="proxy-part">
#shadow-root
<div part="target-me"></div>
</another-custom-element>
</custom-element>
Current efforts were fruitless:
another-custom-element::part(target-me) { }
custom-element::part(proxy-part) another-custom-element::part(target-me) { }
custom-element::part(proxy-part another-custom-element::part(target-me)) { }
custom-element::part(proxy-part::part(target-me)) { }
```
Nope. It is not possible. It kind a breaks the encapsulation principle. The right way is to use proper theming. That means using a combination of:
::part - For direct theming of the component
:host-context - for theming based on the context
::slotted - For styling the slotted element inside the styling
For more dynamic theming, you can use above styles in combination with Element.matches API. Whatever the class/context that the user of the component has set, you can then change the styling of nested children component.
On a side note, modifying the styling of a decadent component (children of children) is a bad practice even when not using Shadow DOM or Web Components. It will result in a brittle non-maintainable CSS.
Edit Note:
:host-context is not implemented in all browsers and probably never will.
Fun twist, it is possible and TIL about exportparts
https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/exportparts
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.
In my angular 6 app. There are many components I have created. For display data I have used ng2-smart-table.
I have some specific requirement to hide default pagination bar. And display custom pagination.
For that I have just set css in component's SCSS file.
::ng-deep .ng2-smart-pagination-nav {
display: none
}
But this is also affects in all other components also.
Till I know and RND on that, In angular we used each component has their each scss file. So my question is why this css affect to all other component also? And how to prevent in this issue ?
The /deep/ combinator works to any depth of nested components, and it
applies to both the view children and content children of the
component
Use
:host Use the :host pseudo-class selector to target styles in the
element that hosts the component (as opposed to targeting elements
inside the component's template).
:host ::ng-deep .ng2-smart-pagination-nav {
display: none
}
Given a typical Angular Material dialog, which has a max-width of 80vw set on .mat-dialog-container, how can I formulate a selector to override it? I'd like a true full-width dialog.
The problem is scoping--Angular-CLI compiles component CSS with scope attribute selectors.
Therefore, this:
.parent .child
becomes:
.parent[some_attr] .child[some_other_attr]
However, this particular element doesn't seem attached to any component--it doesn't have a dynamically-generated attribute on it.
I've attempted overrides in both the dialog stylesheet and the host component's stylesheet with no success.
Angular special selectors
Dialog Plunkr
Let me try again. I'm not doing a good job of explaining the issue.
Let's say I add this to my host component stylesheet:
.mat-dialog-container {
max-width: 100%;
}
I have a build watch running, so the app is recompiled. The CSS output is now this:
.mat-dialog-container[_ngcontent-c6] {
max-width: 100%;
}
However, that element doesn't actually have the attribute _ngcontent-c6 on it. That attribute is applied to other elements which are inside siblings of ancestors of .mat-dialog-container. The selector is just wrong.
If I add that CSS to the dialog component's stylesheet, something similar happens, but with a different attribute ID.
If you can add an id to your main body tag and you want it to be on all of these dialogs you can use this
<style>
#bodyID .mat-dialog-container {
max-width:100vw;
background-color: blue;
}
</style>
It will override the current style, at least in the plunker you supplied.
If you need specific style for each dialog, did you look into this?
how-to-style-child-components-from-parent-components-css-file
You don't need a body id, because as you've mentioned the selector is rewritten by Angular such that it stops matching the element altogether.
But yeah it seems the only way around this is to just throw your hands up and forget about component stylesheet scoping and add your CSS rule to the page stylesheet. The caveat, of course, is that this rule needs to be added to every page that uses the component, which can be seen as absurd depending on what your component is intended to be used for and by whom.
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;
}