_ngcontent-c0 being added to a css rule automatically - css

I was following a drag and drop example in (you can find it here: https://stackblitz.com/edit/draggable-part-6)
After implementing the code I tried to move the "box" into a component.
<div class="box" appDroppable >
MyBox
<div class="box box-helper" *appDraggableHelper>MyBox</div>
</div>
And I noticed it doesn't render correctly. Looking at the chrome dev console I notices that when the element renders outside the box it has the following rule:
When inside the component, it renders the following way:
summary, the "_ngcontent-c0" attribute in not in the html and consequently the rule doesn't apply anymore.
the scss is defined the following way and does not contain any _ngcontent-c0
.box {
background: #BADA55;
border: 1px solid black;
padding: 10px 20px;
display: inline-block;
&.dragging {
background: coral;
}
}
the question is, why is the _ngcontent-c0 being added to the rule dynamically?

That's because Angular hides these classes and limits them to just the component these classes are written for. It's called ViewEcapsulation in Angular.
From Angular's Documentation:
An encapsulation policy for the template and CSS styles. One of:
ViewEncapsulation.Native: Use shadow roots. This works only if
natively available on the platform.
ViewEncapsulation.Emulated: Use
shimmed CSS that emulates the native behavior.
ViewEncapsulation.None: Use global CSS without any encapsulation.
By default, a class that you've defined in the .css file for a component will only be available for use in that component. If you want to use it in some other component, it won't be available. Angular automatically adds these texts to the classes so that they are not accessible outside the component.
thoughtram.io has an amazingly enlightening article on this which you can read here to understand this better.

Related

Styling angular material components from child components

HomeComponent templates includes a router outlet
/* home.component.ts */
...
<mat-sidenav-container>
<mat-sidenav-content>
<router-outlet></router-outlet>
</mat-sidenav-content>
</mat-sidenav-container>
that will render a ListComponent which style should set the overflow of mat-sidenav-content.
Why is the following not working?
/* list.component.css */
:host-context(mat-sidenav-content) { /* same for .mat-sidenav-content */
overflow: unset !important;
}
From my understanding the selector should pick any mat-sidenav-content traversing all the DOM to the root.
I'm afraid this isn't how :host-context works. Host context is for applying styles to the component host conditionally based on it's ancestors. In your example the list component should have overflow: unset but if there was another instance of it without mat-sidenav-content as an ancestor it would not have this. This can be useful for applying styles based on a theme as shown in the documentation here:
https://angular.io/guide/component-styles#host-context
I have included an example on stackblitz with your overflow css and I also set the text to be red in that case so it's more obvious and you can see how it applies to one and not the other. Unfortunately there is not a way to do what I believe you are trying to do which is apply a style to a parent when the component is inside that parent.
The example I have also has ::ng-deep in the other component for completeness, as I have seen used to apply styles to other components by some. I would recommend you stay away from this as well as this style will remain after being first applied(try going to that link and then back to list) and ::ng-deep is deprecated anyway.
https://stackblitz.com/edit/angular-material-sidenav-generate-nav-5fvfjq?file=src/app/list/list.component.css
Edit: The stackblitz has been updated to include an example of :host
It's better to think of the host element in HTML terms rather than as a component, so in the dom <app-list> is the host element rather than what's in the template. If you wanted to style stuff in there you wouldn't need to use :host. I've updated my stackblitz example to include host and if you inspect the css you might get a better idea of how it works.
The HTML looks like this
<app-list _nghost-qnl-c20="">
<p _ngcontent-qnl-c20=""> This text should be red only when inside mat-sidenav-content. The font family is set by host.
</p>
</app-list>
And the css:
mat-sidenav-content[_nghost-qnl-c20], mat-sidenav-content [_nghost-qnl-c20] {
color: red;
}
[_nghost-qnl-c20] {
font-family: Arial, Helvetica, sans-serif;
}
So you can see that host uses an attribute generated by angular and :host by itself is simply that attribute and :host-context(element) becomes element [attribute] in the css.

Angular material overwrite style.css

I'm trying to change the padding on mat-cell and I've noticed some weird behavior.
If I write the css inside the component's css file everything works just fine, but if I write it in style.css (I want to apply it to the whole app) it gets overwritten by the default.
I guess this has to do with the order in which the css files are applied. If that is the case, how can I see this order and is there a way to change it or bring style.css on top?
I would suggest to create a separate .scss file reserved for styling globaly Angular Material elements, and importing it in the main styles.scss file.
Answering your question - propably you're not 'specific' enough. First of all it would be nice to add an additional custom class to your Material element so the custom styles will be applied only when this class is present. Example on styling
.mat-table.my-custom-class {
width: 100%;
.mat-cell {
font-size: 20px;
padding: 20px;
}
}
You might nest the elements event more for higher css specificity
That works for me:
.mat-cell {
padding: 12px!important;
}
Check for the parent scope of default style which is overriding css added in style.css using developer tool. Use the same parental scope along with !important.

Style of accordion-groups' headers (ngx-bootstrap)?

How do I change the style of the accordion headers in ngx-bootstrap?
I tried everything. I copy pasted the code from the documentation for customizing the headers but it does not work. The tag generates a bunch of other tags with classes (mostly bootstrap classes). I get the css path to the heading from the Chrome's Inspector, but I can't change it.
The heading/link is in a <button> tag and even when I say button { color: red !important; } it does not work.
I tried everything, but it does not work.
Thanks in advance!
accordion-group {
::ng-deep {
div {
&>div.panel-heading.card-header.panel-enabled {
background-color: rgba(52, 58, 64, 0.15); // change the background of every accordion heading
.btn-link {
color: rgb(6, 10, 9); // change the accordion heading buttons style
}
}
&>div.panel-collapse.collapse.in.show>div {
background-color: hsla(210, 10%, 83%, 0.10); // change the expanded content style
}
}
}
}
::ng-deep{} - that's how you can change the styles of the component that comes from imported library.
The solution I gave is made with SASS (.scss file). I don't know if you can apply changes to the /deep/ components' styles in a regular CSS. If your Angular project is configurated with CSS you can change it to use SASS syntax with the following line:
ng config schematics.#schematics/angular:component.style scss
You can provide some custom CSS class to the accordion using the panelClass property.
Example
<accordion>
<accordion-group heading="Static Header, initially expanded"
[panelClass]="customClass"
[isOpen]="isFirstOpen">
This content is straight in the template.
</accordion-group>
<accordion-group heading="Content 1">
<p>accordion 1</p>
</accordion-group>
<accordion-group heading="Content 2" panelClass="customClass">
<p>accordion 2</p>
</accordion-group>
</accordion>
Then you need to set the css rules in the global style sheet in you project.
style.css
.card.customClass, .card.customClass .card-header, .panel.customClass {
background-color: #5bc0de;
color: #fff;
}
For more information visit the ngx-bootstrap documentation (Accordion Styling).
Just dealt with this issue after upgrading to most recent versions of angular, bootstrap, etc. and I want to provide a more detailed answer.
My experience is that there's really two main ways to do it
using the [panelClass] attribute and then supplanting the existing styling in the accordion component and its children.
This way is more finicky and will likely take a lot more trial and error to configure to your desired specs.
html:
<accordion>
<accordion-group heading="test" [panelClass]="'custom-class'"></accordion-group>
<accordion-group heading="test2" [panelClass]="'custom-class'"></accordion-group>
</accordion>
note the extra set of quotation marks in the [panelClass] - Angular looks for presets otherwise. You can get around this by initializing a string variable that contains the name of the custom class you desire and popping that in there, instead.
possible css (might not be precise):
accordion-group::ng-deep .custom-class>a{background-color: black !important;}
accordion-group::ng-deep .custom-class>a:hover{color:white !important;}
Track down the specific classes the components utilize (your web browser's developer tools are useful) and use the usual css specs (::ng-deep, !important, '>', etc.), as necessary. In the accordion-group, for example, the headings for accordion-groups utilize .btn, .btn-link, etc.
E.g., if you wanted to change the default underlines in an accordion-group's heading to only display on the (hover) event:
html:
<accordion>
<accordion-group heading="test" id="blah"></accordion-group>
<accordion-group heading="test2"></accordion-group>
</accordion>
css:
#blah .btn{text-decoration: none;}
#blah .btn:hover{text-decoration: underline;}
I find method #2 to be simpler, it just requires a little investigation into the components you use (probably not a bad thing anyway).

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;
}

Dojo FilteringSelect CSS Styles

What are all the css style classes that has to be changed to restyle dojo filtering select ?
Note: I am using claro theme.
I want to
1.Set the style for one particular filteringselect with id QuickSearchPane_SelectBox
2.Set the style for all other filteringselect
I found a few like:
.claro .dijitTextBox .dijitInputInner
.claro .dijitInputField .dijitPlaceHolder
.claro .dijitSelect
But these are not giving the desired effect. I am not even able to change the background colors.
For Menu
[dijitpopupparent="QuickSearchPane_SelectBox"] > .dijitComboBoxMenu .dijitMenuItem
This seems to work.
You can use the following CSS class to start styling your dijit/form/FilteringSelect;
This example will style all instance of dijit/form/FilteringSelect:
https://jsfiddle.net/ofgcd24n/
.dijitInputInner {
background-color: green !important;
}
.dijitMenuItem {
background-color: orange;
}
This other example below will style only ONE instance of dijit/form/FilteringSelect, please note the use of Descendant combinator as selector (where you use the ID for your widget DOM):
#widget_stateSelect .dijitInputInner {
/* your style*/
}
Generally you can use (in Chrome Dev Tool) Event Listen Breakpoints for click/mouse down, so when you open you FilteringSelect, you can block execution, and check with the inspector its HTML structure and see additional CSS classes you want to override with your styles.
More about CSS selector:
https://www.w3.org/TR/css3-selectors/
If you need more details, please post your HTML and CSS and desired layout so we can work out a specific solution.

Resources