CSS-Isolation in Angular 2 Components

Angular 2 provides some useful tools for encapsulating CSS in our components. In this article we’re going to look at how to use CSS encapsulation in Angular.

Let’s use the following "Chess Shop" app as an example to try out these techniques.


The Chess Shop
The Chess Shop

To create specific selectors in SASS, we would nest a single component style within a root ID or class like this:

However, as our apps get more complex and we start creating different components that share the same models, we might end up with SASS selectors like this:

In this scenario, both img selectors apply to the product images. The difference is that the first applies to the product list and the second to a product while inside the watch-list.

We could extract the .product.watch-list to a #watch-list root. But we often end up putting all of the styles of a model in a single file and then override it later by nesting selectors.

Take this HTML for example:

Notice how there is a .product in both sections: a #showcase .product and a #watch-list .product. Let’s create a component for each section and then isolate the CSS. We might refactor this to something like so:

Say we want the showcase to have a different size product image vs. the watch-list. Our first instinct might give us the following stylesheets:

But this would cause a conflict! We’re addressing two different styles with the same selectors. What can we do? Instead of loading these CSS files from the top-level CSS file, instead we can load the CSS in the component.

To do this, we declare the stylesheet using the styleUrls property of ShowcaseProduct:

… and WatchListProduct component::

And the component gets an encapsulated stylesheet! What does it mean to be "encapsulated"? This means that Angular will generate unique selectors that apply only to this component. This means they won’t conflict with any other styles.

To verify that this is true, try using your browser’s developer tools to inspect the CSS class of this component.

Our .product class cannot be overridden by external styles and therefore it becomes encapsulated (i.e. specific to) within the component.

If we want, we can even go further. We don’t even need the .product class anymore… Our components and styles could instead be:

and the WatchListProduct:

and then use these styles:

And these styles won’t conflict with any other img tags in our app!

Differences between Traditional and Angular Components CSS

Here are some of the advantages when using Angular Components CSS:

Global CSS Does Not Conflict With Your Component

Now you won’t have conflicts among selectors with the same names and you won’t need to create CSS to override selectors as frequently!

Special pseudo-selectors in Angular Components

You have new pseudo-selectors like :host and :host-context, we will discuss below.

Simpler selectors

When using Angular Components CSS, you don’t need to nest several selectors in order to reach one single element. This is the best advantage, IMO.

How to load styles into Angular Components

Styles in metadata

The most usual way to add CSS in Angular Components is by adding the styles as array in the component’s metadata. We could rewrite our components like this:

This is my favorite when the component is really small and it has simple CSS. Use it just like you would do with small templates.

With the <style> tag

Another way is to add the <style> tag inside the template itself:

styleUrls metadata

We already used styleUrls in the first examples, it’s just like templateUrl in that it specifies the URL of a CSS file which we will use for this component:

This is useful when you want to separate TypeScript from CSS or the CSS is large.

Special selectors

:host

Usually you can only style elements inside your component, but sometimes we want to modify the styles on the host, that is, the tag the directive is attached to. In order to select the directive tag itself, you use the :host pseudo-selector.

As an example, you can select the <showcase-product> directive itself by using :host

This way you won’t need the <div class="product"> anymore!

:host-context()

This pseudo-selector allows you to change the style of any element within your component depending on the :host‘s ancestry.

In the example below, you can style the img if any of the component’s parent has the #big-deals selector:

When should you not add CSS to Angular Components?

Of course, any tool has it’s downsides, I would not recommend you to use Angular Components CSS when:

  • the HTML/CSS designers work directly in the code but are not comfortable with JavaScript and Angular
  • you want global CSS to mutate the component styles
  • the component is large and complex (though, if this is true, you should consider breaking it down into smaller components anyway)

If you’d like to learn more about building complex Angular apps, checkout ng-book 2!

This post is by the team behind ng-book 2: The Complete Guide to Angular 2. If you’d like to become an Angular 2 expert in a few hours, then checkout ng-book 2.

Felipe Iketani

Hey, Felipe here. I’m the newest ng-book Blog author and a Full-stack Web Developer. I’m also a purple belt Brazilian Jiu-Jitsu fighter who is trying to win a black belt in Angular 2.

Connect with Felipe on Twitter at @felipe_ik.

  • pjetr

    the biggest downside to this, for me, is the lack of sass-variables. In our app, we’ve defined all colours we’ve used as a comprehensive variable. Same for margins and paddings and other stuff we want used consequently throughout the application. While this indeed simplifies the selectors, it takes away the solutions that sass brought to the table.

    • http://ikeif.net keif

      …maybe it’s changed in seven months, but I don’t have this problem.

      I’m using webpack, mind you, but I include the global variable reference in the top of my component (a la @import ‘styles/settings’; ) – and I get everything I need referenced in my component.

  • Sarju

    Is there any option to load external script in component like styleUrls?