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.
Related
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
I have an angular 6 application that uses two different style sheets based off of what role the user has in the system.
Role 1 - Stylesheet 1
Role 2 - Stylesheet 2
The Navbar is a seperate component and is part of the layouts structure of the application.
With new requirements the Navbar must new be styled differently based on which Role the user has.
As you can see the styleUrls only uses one css file. Is there a way to use an ngIF and then if routerLink =/user1 use navbar.css else if routerLink = /user2 use navbar2.css?
#Component({
selector: 'jhi-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['navbar.css']
})
Thanks
So far as I understand what you are looking for isn't available. This is because the css gets compiled into the component code. That means that your css is in your compiled js files and it is scoped to the component that was compiled.
What I do is namespace my css and store both versions in the same file then conditionally add a class at the top level to turn one set of styles on or another.
For example:
<!-- template.html -->
<div [ngClass]="{'role-one': roleOneActive, 'role-two': roleTwoActive}">
<div class="another-class">Cool Code in Here</div>
</div>
Then in your css:
.role-one .another-class {
background-color: blue;
}
.role-two .another-class {
background-color: red;
}
With this when someone has role one the background is blue and if they have role two they will have a red background.
While this isn't ideal because users will download both styles it is the only way if you want to use Angular's styleUrls decorator.
Hope that helps!
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;
}
I have an angular-cli app and using webpack.
When I try to run it the component specific css doesn't work
styles.css
/* You can add global styles to this file, and also import other style files*/
#import 'http://something/v4/dist/css/bootstrap.min.css';
Component
#Component({
selector: 'app-carousel',
templateUrl: './carousel.component.html',
styleUrls: ['./carousel.component.css']
})
export class CarouselComponent implements OnInit {
Component CSS
.carousel-indicators { display: none; }
angular-cli.config
"styles": [
"styles.css",
"../node_modules/roboto-fontface/css/roboto/sass/roboto-fontface-bold.scss",
"../node_modules/roboto-fontface/css/roboto/sass/roboto-fontface-light.scss",
"../node_modules/roboto-fontface/css/roboto/sass/roboto-fontface-regular.scss"
],
The rendered html
<style type="text/css">#import url(http://something/v4/dist/css/bootstrap.min.css);</style>
<style type="text/css">/* You can add global styles to this file, and also import other style files */
</style><style></style><style>.carousel-indicators[_ngcontent-c5] { display: none; }</style>
but this is not applied to my html element 'carousel-indicators'
If I import the carousel.component.cssinto the styles.css then it works but it appears twice in the generated html
I'm looking for the right way of doing this
By default(as in your case) angular using ViewEncapsulation.Emulated that scopes your css. However there is 3 view encapsulation options in Angular:
Native view encapsulation uses the browser's native shadow DOM implementation (see Shadow DOM on the MDN site) to attach a shadow DOM to the component's host element, and then puts the component view inside that shadow DOM. The component's styles are included within the shadow DOM.
Emulated view encapsulation (the default) emulates the behavior of shadow DOM by preprocessing (and renaming) the CSS code to effectively scope the CSS to the component's view. For details, see Appendix 1.
None means that Angular does no view encapsulation. Angular adds the CSS to the global styles. The scoping rules, isolations, and protections discussed earlier don't apply. This is essentially the same as pasting the component's styles into the HTML.
So when you applying any styles to your component in component.css(with default ViewEncapsulation.Emulated) the styles will be applied just for that particular component, it won't be leaked outside the component and always have a priority above the global styles unless global style has !important.
So as a result you have the style in the head of your html file like:
<style>.carousel-indicators[_ngcontent-c5] { display: none; }</style>
If you referencing your component.css in styles.css then it will became a global style rendered in html head like so:
<style type="text/css">/* You can add global styles to this file, and also import other style files */
.carousel-indicators {
display: none; }
</style>
As you declared you style in competent and then referenced your component.css in styles.css that competent styles just gets doubled in your html: one copy is a global style and other copy is scoped component styles.
I was tried to replicate you issue but my compentnt.css is always gets applied. I am using the latest stable angular cli 1.3.2. If you are using older cli try to update. Otherwise push your code on github or create a plunker so I can take a look.
UPDATE: You might have your custom css gets overridden by some of your global stylesheets you are referencing. You can use chrome dev tools to debug the styles also you can try to put !important to your custom css and see if it does help.
For everybody landing here :
The issue was with the ViewEncapsulation.Emulated I changed it to ViewEncapsulation.None as describe in this stackoverflow answer :
how to hide ngb-carousel indicators and prev-next control
Thanks for your help
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;
}