“ViewEncapsulation” in Angular
Ah, ViewEncapsulation
!
It’s what keeps you asleep through the night! Or does it? 😊
Let’s refresh our knowledge about ViewEncapsulation
.
ViewEncapsulation.Emulated
By default, all Angular components come with something called “style encapsulation”. It means that a component “encapsulates” its own styles so they only apply to elements within its scope. Styles defined in one component will not have an effect on the elements in another component.
Angular achieves this by adding a specific attribute to the component’s host element and applying the same attribute to all the CSS selectors provided via Component#styles
or Component#styleUrls
. (taken from Angular’s docs)
Considering a component to be an independent unit, this is the expected behaviour. You don’t want your components to “leak” styles that affect “outside” elements.
The above is done by setting the Component.encapsulation
option to ViewEncapsulation.Emulated
(or not setting it at all since that’s the default value).
Looking at the DevTools in the Figure 1 below, you can see that the my-app
component has a _nghost-ng-<id>
attribute. The same <id>
is also added to the _ngcontent-ng-<id>
attribute present on all child elements.
Note that the <id>
is auto-generated by Angular and you should not rely on it being the same every time. So don’t style elements with _ngcontent-ng-abc123
!
ViewEncapsulation.None
View encapsulation can be turned off on a component by setting the Component.encapsulation
option to ViewEncapsulation.None
.
But beware! Turning view encapsulation off means that all of the component’s styles now apply globally. They will no longer be scoped to the component, and can therefore affect any HTML element in the application.
You can see that by inspecting the component’s elements in DevTools:
Figure 2 above shows us that the _nghost-ng-<id>
attribute is no longer present on the my-app
component, nor on any child elements. Styles added to h1
will now “leak” from the component and affect any other h1
s on the page. Had there been another h1
on the page, even in a completely different component, the color: tomato
style would be applied to it.
There are valid reasons for turning encapsulation off, e.g. styling 3rd party components, or because parts of a component are dynamically created/moved to some other part of the DOM, e.g. a modal that is created as a child to body
. Whatever the case, beware that the styles you add to a component might have an effect on unrelated elements!
But what if you want to disable view encapsulation on a component but still keep some, or all of its styles scoped to the component?
You can achieve this by nesting the styles under the component’s selector, i.e.
my-component {
h1 {
color: tomato;
}
}
ViewEncapsulation.ShadowDom
Component.encapsulation
can take a third value - ViewEncapsulation.ShadowDom
but so far I’ve never used it in my apps. Once set, it uses the browser’s native Shadow DOM API to encapsulate CSS styles, … (taken from Angular’s docs).
It looks like this in DevTools:
I don’t have experience with ShadowDom
, so I’ve included it only for reference. You can decide for yourself whether it makes sense to use it in your apps.
Well, that’s it! I hope you learned something new about style encapsulation in Angular.
See you in the next post 👋