When and Why Should We Use View Encapsulation in Angular

When and why should we use View Encapsulation in angular

Codecraft.TV has an amazing article on ViewEncapsulation that you can refer to get a better understanding.

To just summarize it:

ViewEncapsulation.Emulated: Angular changes our generic css class selector to one that target just a single component type by using automatically generated attributes.

Any styles we define on a component don’t leak out to the rest of the application but with ViewEncapsulation.Emulated our component still inherits global styles.



ViewEncapsulation.Native: If we want Angular to use the shadow DOM we can set the encapsulation parameter to use ViewEncapsulation.Native

With ViewEncapsulation.Native styles we set on a component do not leak outside of the components scope.

This is great if we are defining a 3rd party component which we want people to use in isolation. We can describe the look for our component using css styles without any fear that our styles are going to leak out and affect the rest of the application.

However with ViewEncapsulation.Native our component is also isolated from the global styles we’ve defined for our application. So we don’t inherit the global styles and have to define all the required styles on our component decorator.

Finally ViewEncapsulation.Native requires a feature called the shadow DOM which is not supported by all browsers.



ViewEncapsulation.None: If we don’t want to have any encapsulation at all, we can use ViewEncapsulation.None.

If we don't encapsulate anything, the style we defined in the component will leak out and started affecting the other components.

Some other resources that you might want to have a look into:

  1. VIEW ENCAPSULATION IN ANGULAR - By Thoughtram
  2. View Encapsulation by Rangle.IO
  3. Scoping Your Styles in Angular With ViewEncapsulationView
  4. Diff between ViewEncapsulation.Native, ViewEncapsulation.None and ViewEncapsulation.Emulated

How default view encapsulation works in Angular

There are three types of encapsulation in angular

  • ViewEncapsulation.Emulated and this is set by default
  • ViewEncapsulation.None
  • ViewEncapsulation.Native

Emulated mode

Assume that you have two different components comp-first and comp-second , For example you define in both of them

<p> Some paragraph </p>

So if you apply some styling for paragraph in comp-first.css

p { 
color: blue;
}

and then inspect p element on comp-first.html and look for its styling will find something like this

p[_ngcontent-ejo-1] {
color: blue;
}

"_ngcontent-ejo-1" is just a simple key for differentiate such an element from others components elements

None mode

If you apply this mode to such a component for instance comp-first and then you go and inspect any element it will not provide any attribute like "_ngcontent-ejo-1" to any element , So applying any styling or class it will be provided globally .

Native mode

This should give the same result as if you are using emulated mode but it comes with Shadow DOM technology in browsers which support it

Angular view encapsulation with external libraries

You can define this in your css. However, be carefull as ::ng-deep is quite a powerfull combinator and can cause problems if not used correctly.
Also from the Angular website:

The shadow-piercing descendant combinator is deprecated and support is being removed from major browsers and tools. As such we plan to drop support in Angular.

CSS:

 :host { color: red; }

:host ::ng-deep parent {
color:blue;
}
:host ::ng-deep child{
color:orange;
}
:host ::ng-deep child.class1 {
color:yellow;
}
:host ::ng-deep child.class2{
color:pink;
}

HTML:

  Angular2                                //red
<parent> //blue
<child></child> //orange
<child class="class1"></child> //yellow
<child class="class2"></child> //pink
</parent>

Diff between ViewEncapsulation.Native, ViewEncapsulation.None and ViewEncapsulation.Emulated

update
If you want styles that are added to Parent applied to Child you need to set ViewEncapsulation.None in the Child component so it doesn't prevent styles to bleed in.

Emulated and Native are just two different ways to prevent styles to bleed in to and out from components. None is the only one that allows styles to cross component boundaries.

original

  • ViewEncapsulation.None is simple no encapsulation

  • ViewEncapsulation.Emulated (currently the default in Angular2)

    adds attributes to component tags and child elements and manipulates the CSS (adding the attributes to the selectors) added to the page so the styles don't bleed into each other - to keep styles scoped to the components where they are added even though the styles are all added collected in the head of the page when components are loaded.

  • ViewEncapsulation.Native creates custom elements with shadow DOM where the browsers native implementation ensures the style scoping.

    If the browser doesn't support shadow DOM natively, the web-components polyfills are required to shim the behavior. This is similar to ViewEncapsulation.Emulated but the polyfills are more expensive because they polyfill lots of browser APIs even when most of them are never used. Angulars Emulated emulation just adds the cost for what it uses and is therefore much more efficient for Angular applications.

View Encapsulation Emulated, is it possible to escape emulated encapsulation within a stylesheet?

This is where the (deprecated) ::ng-deep comes in play:

In your templates stylesheet:

:host ::ng-deep .ui-resizable-handle {
background-color: pink;
}

This will target any child element with the class ui-resizable-handle from your component, regardless if it's declared in the template, a child component or dynamically added with a third party library, because this will compile to something like:

[_nghost-fav-c294] .ui-resizable-handle {
background-color: pink;
}

ViewEncapsulation ShadowDom vs Emulated

Answer: ViewEncapsulation.Emulated will add the css style in the head section of your website(and reference your component's unique id(_ngcontent) to apply it).
ViewEncapsulation.ShadowDom will add the css style inside the generated DOM of your component.

You could decorate your component with these two encapsulation and see the change in the style declaration in your website.

Note: ShadowDom is not supported by some of the legacy browsers.

Now performance-wise I think that ShadowDom will be better as the style are declared inside your component's div.

While Emulated will be better if you want to target the legacy browser as well.

ViewEncapsulation.Emulated styles are copied into #shadow-root by a ViewEncapsulation.(Native|ShadowDom) component

It's a known bug, the workaround at the moment is to basically not mix encapsulation modes.

But the scenario i assume you are encountering might be that you are mixing third parties having different types of encapsulation modes? If so you either have to take in consideration of your css structure or just simply rethink what third-party lib you are mixing.

Update

In consideration to comment make all components to run native encapsulation by telling compiler to do so with compilerOptions in order to not conflict with native web components.

Do so by adding in your tsconfig.json file(it's tsconfig.app.json in ng version 6+):

"angularCompilerOptions": {
"defaultEncapsulation": 1
}

Is it possible to style using :host with Encapsulation.None in Angular?

The component selector can be used as the CSS selector to style the host element when the encapsulation is set to ViewEncapsulation.None:

/* With ViewEncapsulation.Emulated, use :host selector */
:host {
color: red;
}

/* With ViewEncapsulation.None, use component selector */
app-child-encapsulation-none {
color: green;
}

See this stackblitz for a demo.



Related Topics



Leave a reply



Submit