54

Can some one explain what's the difference between ViewEncapsulation.Native, ViewEncapsulation.None and ViewEncapsulation.Emulated in angular2.

I tried to google it and read some articles, but I'm not able to understand the difference.

Below I have two components Home (home.ts) i.e. parent component and MyComp (my-comp.ts). I want to define styles in the parent that are being used in the child component.

Should I use ViewEncapsulation.Native or ViewEncapsulation.None

home.ts

import {Component, ViewEncapsulation} from 'angular2/core';
import {MyComp} from './my-comp';
@Component({
  selector: 'home',  // <home></home>
  providers: [
  ],
  directives: [
    MyComp
  ],
  styles: [`
    .parent-comp-width {
       height: 300px;
       width: 300px;
       border: 1px solid black;
     }
    `],
  template:`
    <my-comp></my-comp>
    <div class="parent-comp-width"></div>
  `,
  encapsulation: ViewEncapsulation.Native
})
export class Home {
}

my-comp.ts

import {Component} from 'angular2/core';

@Component({
  selector: 'my-comp',  // <home></home>
  template: `
  <div class="parent-comp-width">my-comp</div>
  `
})
export class MyComp {
}
Brampage
  • 6,014
  • 4
  • 33
  • 47
Parmod
  • 1,213
  • 1
  • 10
  • 18
  • My suggestion is to always use `ViewEncapsulation.None`. At least until you know that you need others (; – Sasxa Feb 26 '16 at 13:36
  • 1
    Yes, if you don't care about view encapsulation just set it to `None` everywhere, then you have the behavior common in pre-web-component times. – Günter Zöchbauer Feb 26 '16 at 13:38

6 Answers6

48

update If you want styles that are added to Parent applied to Child you need to set ViewEncapsulation.None in the Parent 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.

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 1
    **None is the only one that allows styles to cross component boundaries** But in above code child component able to access parent-comp-width css class. – Parmod Feb 26 '16 at 15:16
  • @Gunter can you please elaborate ViewEncapuslation.Native as i am not able to figure that out , it will be great if u can – Rahul Singh Mar 12 '17 at 07:42
  • @RahulSingh sorry, no idea what to exlaborate on. It uses the browsers shadow DOM implementation. It is probably not a good idea to use it right now, because there are no good strategies for styling and themeing available currently. – Günter Zöchbauer Mar 12 '17 at 13:14
  • Per my answer below, ::ng-deep is another (soon-to-be-deprecated) way to apply parent styles to child components. See https://stackoverflow.com/questions/36527605/how-to-style-child-components-from-parent-components-css-file – Aaron Dec 10 '17 at 00:28
  • 5Soon to be deprecated" isn't actually the case. It was marked deprecated at the time it was added because `ViewEncapsulation.Emulated` will eventually go away when alk browsers support shadow DOM end theming properly. – Günter Zöchbauer Dec 10 '17 at 09:01
  • Is it fair to say that ViewEncapsulation.None would be better for performance? Or would the difference be negligible? – abyrne85 Feb 19 '19 at 11:44
  • 1
    @abyrne85 it's not really performance related. I don't think it will make a notable difference. – Günter Zöchbauer Feb 19 '19 at 12:16
  • What happens if you set View Encapsulation to none in the parent and not the child? – Collin Oct 12 '21 at 17:56
  • @CollinFox view encapsulation only is about styles from ancestors leaking into descendants. Setting it on the parent only affects the parent. The child has its own setting. – Günter Zöchbauer Oct 13 '21 at 09:51
  • Ah that's why setting view encapsulation to none in the parent of my component fixed a style in the parent. a parent of the parent must have had a necessary style defined that was not leaking into the parent when it should have. Thanks – Collin Oct 13 '21 at 15:10
  • @CollinFox that sounds right – Günter Zöchbauer Oct 14 '21 at 11:09
9
  • Native: Uses browser's native Shadow DOM. Check for browser support before enabling it.
  • ShadowDom: Uses browser’s native Shadow DOM v1 for better cross-browser support and is a shared standard across the browsers. Check the difference between Shadow DOM v0 to v1.
  • Emulated: Imitates behavior of Shadow DOM to scope the CSS for component and appends to the head.
  • None: Neither Shadow DOM nor custom implementation, like global CSS which gets appended to the head

Angular uses ViewEncapsulation.Emulated as default encapsualtion mode.

Hardik Pithva
  • 1,729
  • 1
  • 15
  • 31
7

Let's take for an example the scenario where the ComponentParent contains ComponentChild. For this example we are discussing different encapsulation scenarios for the ComponentParent.

import { ViewEncapsulation }  from '@angular/core';

@Component({
  selector: 'component-child',
  // templateUrl: './child.component.html',
  template: '<h1>Hello, child</h1>',
  // styleUrls: ['./child.component.scss'],
  style: '/* ... */'
})
export class ComponentParent {
  // ...
}

@Component({
  selector: 'component-parent',
  template: '<h1>Hello, parent</h1><component-child/>',
  style: 'h1{background-color:yellow}',
  encapsulation: ViewEncapsulation.Emulated // this is the default encapsulation for the angular component
})
export class ComponentParent {
  // ...
}

ViewEncapsulation has 1 obsoleted value:

and 3 valid values:

None

This is the transparent mode and something the most similar to the scenario where angular is not involved at all.

Both ComponentParent and ComponentChild will have H1 tag with yellow background.

ShadowDom

This mode creates a native shadow DOM root around the component (in our case: ComponentParent) content. This will protect any (CSS/SASS) style we declare inside the component to leak OUTSIDE the component. However, it will apply to child components like ComponentChild.

Both ComponentParent and ComponentChild will have H1 tag with yellow background (similar to the None mode), but any H1 tag outside the ComponentParent will NOT be affected.

Emulated

In short, this applies the styles declared in the ComponentParent ONLY and ONLY to the ComponentParent content, but EXCLUDING the child components like ComponentChild. In other words, only on "pure" HTML elements, but not angular web (component) elements.

Only ComponentParent will have H1 tag with yellow background.

Additional explanation on Emulation mechanism

The Emulated mode is usually transparent to us, as we prefer to put our global styles (affecting both ComponentParent and ComponentChild) which WILL penetrate both None and Emulated components and their children components and HTML elements.

However imagine the ComponentChild is a 3rd party component and you want to style it. You will NOT be able to do that with the Emulated mode applied on the ComponentParent component. This is due to the Emulated implementation:

EACH HTML element inside the ComponentParent component will be decorated with the component-name attribute (without value), for example:

  • _nghost-c3: for the component container
  • _ngcontent-c3: for the component's content

In parallel EACH (S)CSS selector in our component ComponentParent will be "encapsulated" (conditioned) with the same component-name attribute

.H1[_ngcontent-c3] {
  background-color:yellow;
}

Overall, this means, that only elements of the ComponentParent will be affected, and our aim to decorate H1 of the 3rd party component will fail, as it doesn't have the (same, if any) component-name attribute (_ngcontent-c3)

Solutions for the 3rd party components:

  • Use the ShadowDom if available
  • Disable encapsulation, use None
  • put styles in global (S)CSS
  • simulate emulation for inner 3rd party components by decorating their elements with the component-name attribute
mPrinC
  • 9,147
  • 2
  • 32
  • 31
1

from pro-angular book:

The ViewEncapsulation Values:

  • Emulated: When this value is specified, Angular emulates the Shadow DOM by writting content and styles to add atrributes.This is default behaviour if no encapsulation value is specified.

    If you inspect the DOM using the browser’s F12 developer tools, you will see that the contents of the external CSS file.

    ...
    <style>
    div[_ngcontent-c0] {
      background-color: lightcoral;
    }
    </style>
    ...

The selector has been modified so that it matches div elements with an attribute called _ngcontent-c0 although you may see a different name in your browser since the name of the attribute is generated dynamically by Angular.

To ensure that the CSS in the style element affects only the HTML elements managed by the component, the elements in the template are modified so they have the same dynamically generated attribute, like this:

...
<div _ngcontent-c0="" class="form-group">
   <label _ngcontent-c0="">Name</label>
   <input _ngcontent-c0="" class="form-control ng-untouched ng-pristineng-invalid" 
        ng-reflect-name="name" name="name">
</div>
...
  • Native: When this value is specified, Angular uses the browser’s shadow DOM feature. This will work only if the browser implements the shadow DOM or if you are using a polyfill.
  • None: When this value is specified, Angular simply adds the unmodified CSS styles to the head section of the HTML document and lets the browser figure out how to apply the styles using the normal CSS precedence rules.

The Native and None values should be used with caution. Browser support for the shadow DOM feature is so limited that using the Native option is sensible only if you are using a polyfill library that provides compatibility for other browsers.

The None option adds all the styles defined by components to the head section of the HTML document and lets the browser figure out how to apply them. This has the benefit of working in all browsers, but the results are unpredictable, and there is no isolation between the styles defined by different components.

fgul
  • 5,763
  • 2
  • 46
  • 32
0

If anyone's getting to this question because they want to style child components via parent component style declarations, see this SO answer.

However, as the latest comment on the accepted answer indicates, the Angular docs say:

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 (for all 3 of /deep/, >>> and ::ng-deep). Until then ::ng-deep should be preferred for a broader compatibility with the tools.

Aaron
  • 2,049
  • 4
  • 28
  • 35
-1

Please refer below example to understand all three options :

encapsulation: ViewEncapsulation.Emulated
encapsulation: ViewEncapsulation.Native
encapsulation: ViewEncapsulation.None

Click here to see the example

Tejas Savaliya
  • 572
  • 7
  • 8