CSS encapsulation has always been something developers have wanted in their web applications. The ability to scope CSS to a specific component without affecting other components has been difficult to achieve. This post we will cover how to use Angular 2 components to encapsulate our CSS and learn the pros and cons to each technique. This post has been updated to the latest Angular 2 RC5.

In our Angular 2 app we will have three components. First is our App component, it will have two child components FirstComponent and SecondComponent.

Rendered output of Angular 2 CSS encapsulation



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

@Component({
  selector: 'demo-app',
  template: `
    <h3>CSS Encapsulation with Angular 2</h3>
    <div class="cmp">
      App Component
      <first-cmp></first-cmp>
      <second-cmp></second-cmp>
    </div>
  `
})
export class App {
  constructor() { }
}


We link a separate style sheet into our index.html that has a single global style rule that will be applied to any element with the CSS class of cmp.



.cmp {
  padding: 6px;
  margin: 6px;
  border: 2px solid red;
}


Style Techniques

Now lets take a look at our FirstComponent and SecondComponent and see the options we have to style these components.



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

@Component({
  selector: 'first-cmp',
  template: `
    <div class="cmp">First Component</div>
    <style>.cmp { border: blue 2px solid; }</style>`
})
export class FirstComponent {
  constructor() { }
}

@Component({
  selector: 'second-cmp',
  template: `<div class="cmp">Second Component</div>`,
  styles: ['.cmp { border: green 2px solid; }']
})
export class SecondComponent {
  constructor() { }
}


So looking at our two components there are two different ways to apply styles to them. In FirstComponent we have a style tag in out template while in the SecondComponent we can use a styles property on our component decorator. Both will have the same outcome when rendering to the screen.

View Encapsulation

Angular by default encapsulates component CSS. So lets take a look at the rendered output of our code so far.

Rendered output of Angular 2 CSS encapsulation

So we can see that each components corresponding .cmp CSS class is scoped to it’s own template. The default CSS behavior multiple .cmp classes would of caused global name collisions with our styles. So lets look at the Chrome dev tools and see what the rendered HTML and CSS looks like.

Rendered output of Angular 2 CSS encapsulation

By default Angular 2 generates attributes to help scope our CSS class names to our given component. So you can see here all elements inherit the .cmp CSS. Each component’s CSS is scoped and overrides our base border color. The attributes generated by Angular should NOT be used to target elments with CSS. These attributes are automatically generated can can change.

Native CSS encapsulation with Shadow DOM

Angular has some additional CSS rendering options. The first is we can use Native CSS encapsulation. Turning on this feature will force browsers to use the Shadow DOM. For browsers that understand the Shadow DOM this creates a new rendering context for a given element that is completely isolated from the rest of the DOM. This is true native CSS encapsulation but is not enabled by default in Angular 2. So lets look at the code and the generated output.



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

@Component({
  selector: 'second-cmp',
  template: `<div class="cmp">Second Component</div>`,
  styles: ['.cmp { border: green 2px solid; }'],
  encapsulation: ViewEncapsulation.Native  // Use the native Shadow DOM to encapsulate our CSS
})
export class SecondComponent {
  constructor() { }
}


Rendered output of Angular 2 CSS Native encapsulation

So here we can see a shadow root element being created which isolates our SecondComponent from the rest of our application. One thing to note this behavior is slightly different than the default behavior. This isolates the component completely so we do not inherit the global .cmp styles with that had our padding and margin.

Rendered output of Angular 2 CSS Native encapsulation

If we want the default global CSS to apply to elements in the shadow DOM we must use a special CSS selector.



::shadow .cmp {
  padding: 6px;
  margin: 6px;
}


Disable CSS Encapsulation

Sometimes although rare, there are occasions where we would like a component’s CSS to not be encapsulated and apply globally to our application. Angular offers an easy way to disable CSS encapsulation. So lets disable this on our SecondComponent.



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

@Component({
  selector: 'second-cmp',
  template: `<div class="cmp">Second Component</div>`,
  styles: ['.cmp { border: green 2px solid; }'],
  encapsulation: ViewEncapsulation.None  // Use to disable CSS Encapsulation for this component
})
export class SecondComponent {
  constructor() { }
}


Now that we disabled our CSS/View Encapsulation lets look at how our app is rendered.

Rendered output of Angular 2 disabled CSS encapsulation

So we can see in our SecondComponent the .cmp CSS class set the border to green. Since encapsulation is disabled it is now applied globally. This overrides the default global of red making our root app component have a green border. Notice our FirstComponent still has a blue border. This is because our FrstComponent still has the default View Encapsulation. If CSS is needed to be shared across components create global utility classes and do not copy the CSS over and over between components.

With Angular 2 Components we have far more control with our CSS styles. Check out the full working demo in the link below.

Demo