52

I've got some CSS rules in my Angular 2 app that would be common across various components. Obviously I don't want to copy&paste them into each component's styles. I currently have 2 ideas:

  1. Place common CSS rules in a static CSS file and include it using a link in my index.html's head section.
  2. Place my common CSS rules in one or more files and include them in @Component decorator for each component, e.g. styleUrls: [ './myComponentStyle.css', '../common/common.css']

First approach look not-so-angular-ish to me, but at the same it's sure to work and simple to implement.

Second one requires some work to be done with each component, but allows more control about what styles are being used by one. It also lets me to organize my common styles into smaller stylesheets and use only ones that are needed.

Do you favor any of those solutions or is there a third, better one? :)

Paolo
  • 20,112
  • 21
  • 72
  • 113
krazimierz
  • 521
  • 1
  • 4
  • 5

3 Answers3

59

1. This solutions is good, but it's more suitable for any common styles, which should be available for all components. For example, styles for css grids. To make it more angularish you could set encapsulation for you app component to none:

`@Component({
     selector: 'my-app',
     template: `  `,
     styleUrls: ["shared.style.css"],
     encapsulation: ViewEncapsulation.None
}) export class App {}`  

Demo could be found here (plunker)

Note: Styles, included by this ways (just adding style tag, or with non encapsulation) will affect all elements on your pages. Sometimes it is want we really want (agreement to use any css framework for hole project). But if just want to share styles between few component - it would be probably not the best way.

 Summary: 
 (+) easy to use
 (-) no encapsulation

2. I like this solution, because it is very understandable and has predictable behavior. But there is one problem with it:

It will add style tag with your shared styles every time you use it. It could be a problem if you have big style file, or many element which are using it.

duplicated styles

@Component({
   selector: 'first',
   template: `<h2>  <ng-content> </ng-content> </h2>`,
   styleUrls: ["shared.style.css"]
})
export class FirstComponent {}

Demo could be found here (plunker)

 Summary:
 (+) easy to use
 (+) encapsulation
 (-) duplicates styles for every usage

3. There is one more option you could use. Just create one more component which will provide shared styles for it's children.

  ` <styles-container>
    <first> first comp  </first>
  </styles-container>
  <styles-container>
    <second> second comp </second>
  </styles-container>`

In those case you will have to use /deep/ in your styles to make style available for child components:

:host /deep/ h2 {
  color: red;
}

I also worth to be mentioned not to forget use :host to make styles available only for child elements. If you omit it you will get one more global style.

Demo could be found here (plunker)

Summary:
(-) you have to create container and it in templates
(+) encapsulation
(+) no duplicated styles

Notes: Encapsulation of styles is really cool feature. But you also should remember that there no way to limit your deep styles. So if you applied deep styles, it would available absolutely to all children, so use it careful too.

ilyabasiuk
  • 4,270
  • 4
  • 22
  • 35
  • Hey there, great answer! Regarding #3, I've read that `:host` and `/deep/` will be deprecated? Is it still sustainable to use #3 in the long run then? https://angular.io/guide/component-styles#deprecated-deep--and-ng-deep – wentjun Jan 31 '19 at 02:17
  • 1
    That's not easy question. You could read this answer to get more understanding, what's going on with deep: https://stackoverflow.com/questions/47024236/what-to-use-in-place-of-ng-deep – ilyabasiuk Feb 01 '19 at 11:41
  • I liked the second solution. – Vikash Choudhary Nov 28 '19 at 06:20
  • For 3. and current Angular you'd need to replace `host: /deep/` with `styles-container`, as `host:` does not work with `ViewEncapsulation.None`! – daniel-sc Nov 04 '21 at 10:50
1

There are 3 ways to use styling in angular2 app (link). You have mentioned two of those that allows you to reuse styles.

My personal opinion is that for any large application its preferable to go with #2 mainly due to the view encapsulation provided by angular.

#1 can be used for the really very generic styles that are common to all parts of your application. But if you will take into account that the root in your SPA will be angular component anyway - there is no real need to go with another approach of linking styles than #2.

Moreover by working with css in two different ways you will have to remember this (and handle with some extra code) when for example bundling your app and using tools like gulp-inline-ng2-template

Amid
  • 21,508
  • 5
  • 57
  • 54
0

For future readers, I think this solution is best.

Let's assume you have 2 components(products and customers), and have common styles to be shared.

1.Create one more component

//customer-products-styles.component.ts
@Component({
  selector: "app-customer-products-styles",
  template: "",
  styleUrls: ["./customer-products-styles.component.scss"],
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class CustomerProductsStylesComponent {}
//customer-products-styles.component.scss
app-products,
app-customers {
  p {
    color: coral;
  }
}

2.Use it like so

<!-- Customers Component (app-customers) -->
<app-customer-products-styles></app-customer-products-styles>
<p>
  customers works!
</p>
<!-- Products Component (app-products) -->
<app-customer-products-styles></app-customer-products-styles>
<p>
  products works!
</p>

Benefits

  • It is lazy-loaded, loads when module chunk is downloaded, initial main.js is reduced
  • Adding component selectors (app-customers and app-products) as a parent for styles make it component scope
  • No duplicate styles and only load once in the browser, whatever the component request it first

Some Additional points

  • Set encapsulation to none, but add component selector as parent in the style
  • I also changed default changeDetection to OnPush, there is no need but to be safe

Working Stackblitz

Sameer
  • 4,758
  • 3
  • 20
  • 41