Reputation: 2475
I'm trying to style an element placed by the router outlet in angular and want to make sure that the element generated gets a width of 100%
From most of the replies, I'm seeing that I should use the ::ng-deep
selector, but from Angular's docs it is being deprecated. Is there an alternative to ::ng-deep
?
Upvotes: 230
Views: 209766
Reputation: 3587
Update 2024: ::ng-deep is going nowhere! Still, the Angular team strongly advises to use it as the last resort.
As someone stated before, if you're using a third party library it's virtually impossible to avoid the ::ng-deep
once in a while.
Let's have a look to some alternatives
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.scss'],
encapsulation: ViewEncapsulation.None
})
Be aware that breaking the encapsulation of the component will make the styles globally available. I can think in 2 ways to avoid collisions and CSS weirdness:
<section class="app-example-container">
<!-- a third party component -->
<mat-tab-group>
<mat-tab label="First"></mat-tab>
<mat-tab label="Second"></mat-tab>
</mat-tab-group>
</section>
Now, since there's no Encapsulation you can modify the third party component by targeting their classes. That said, example.component.scss should be like:
.app-example-container {
/* All the CSS code goes here */
.mat-tab-group .mat-tab-label {color: red;}
}
app-example {
/* All the CSS code goes here */
.mat-tab-group .mat-tab-label {color: red;}
}
As simple as adding a new CSS file to your styles array of your angular.json
configuration file. Be aware that this will eventually become harder and harder to maintain. Personally, I'd avoid this option or use it as a last resort :)
I will agree that it's a bit painful because you can't include Styles in a directive (in the same way you can do it in a Component), but it can be handy sometimes. You could also use a component to apply the styles the same way the Angular Material team did with the buttons
You already know about this one, just wanted to make clear that using it together with the host selector is the Angular recommended way to avoid potential styles collisions.
A self note to the future: https://angular.io/guide/component-styles
That should be the first place to look at for official alternatives/ways-to-go
Edit 1. As @beppe9000 mentioned in a comment, ::ng-deep is an Angular thing. Even if the Angular team remove this feature tomorrow, your already deployed app will continue working. The confusion arose because of the old /deep/
modifier.
Upvotes: 35
Reputation: 1410
The simple and easy alternative to a deep style is a common style using the element selector of the parent component. So if you had this in hero-details.component.css
:
:host ::ng-deep h3 {
font-style: italic;
}
It would become this in your root styles.css
:
app-hero-details h3 {
font-style: italic;
}
Basically a deep style is an un-encapsulated style so it conceptually seems more like a common style to me than a component style. Personally I would not use deep styles anymore. Breaking changes are normal in major version updates and deprecated feature removal is fair game.
Upvotes: 93
Reputation: 298
Use the :host-context
selector in the child component's encapsulated style as a non-deprecated alternative:
:host-context(.some-class) .your-element {
/* styles that will apply when a parent element has the 'some-class' class */
}
https://blog.angular-university.io/angular-host-context/
Upvotes: 4
Reputation: 1263
If you want to style some 3rd party component which is used across the site in several places, but you need specific CSS look in one place without affecting other occurences after visiting THIS page - you can use [ngStyle]
.
I understand it's not suitable for all situations, but in my cases it is a way to go (I need to have ViewEncapsulation.None
, so I cannot isolate styles in the separate CSS file).
Upvotes: 0
Reputation: 666
You can use "/deep/". It's ::ng-deep alternative.
:host /deep/ h3 {
font-style: italic;
}
Upvotes: -16
Reputation: 13933
FWIW In my research I have not found any replacement for ng-deep or the other applicable alternatives. This is because, I believe, the Angular team is deferring to the W3C spec on the shadow dom, which initially had selectors such as deep
. However, the W3c has since removed the recommendation, but not replaced it with a new one. Until that happens, I imagine that the Angular team will keep ::ng-deep
and it's alternatives available, but in deprecated state due to the pending state of W3C's drafts. I am not able to take the time to find the documentation to back this up right now but I did see it recently.
Long story short: Keep using ::ng-deep
and its alternatives until a replacement is created - the deprecation is just an early notice so that people aren't blindsided whenever the actual change materializes.
-- UPDATE --
https://drafts.csswg.org/css-scoping-1/ Here is the draft proposal if you're interested. It appears that they are working on a robust set of selectors for elements within a shadow dom tree; it is this spec, once approved, that I think will inform the angular clone, if there even is one (i.e. angular may not need to implement their own selectors once this goes live in browsers).
Upvotes: 229
Reputation: 39
This is not a general replacement for ::ng-deep, but for the use case described by the question author:
In the special case where you want to style the element inserted by a router-outlet, there is an elegant solution using the adjacent neighbor selector in CSS:
router-outlet+* {
/* styling here... */
}
This will apply to all elements which are direct neighbors of a router-outlet.
Further reading:
https://developer.mozilla.org/en-US/docs/Web/CSS/Adjacent_sibling_combinator
https://angular.io/guide/router#router-outlet
Upvotes: 3
Reputation: 18849
To bypass the deprecated ::ng-deep
, I usually disable ViewEncapsulation
. Although this is not the best approach, it has served me well.
To disable ViewEncapsulation
, do the following in your component:
import { Component, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class HeaderComponent {
}
This will make the .scss styles in this component global to the whole application. To not allow the styles to go up the chain to parent and sibling components, wrap the whole scss with the selector like so:
app-header {
// your styles here and any child component styles can go here
}
Now, the styles specified here will go down to children components so you have to be extra specific with your css selectors and mind your p's and q's when adding CSS (maybe add the child selector specified in your Angular app and then its styles).
I say it is not the best approach because of the paragraph above, but this has served me well.
Upvotes: 36