17

By default, Angular 2 compiles the CSS into JavaScript, especially when using WebPack as in Angular-CLI. I would rather this not happen for a couple of reasons.

The first reason is that when I'm developing, I find it really helps to be able to see in the developer tools exactly what style sheet a specific style rule was coming from and what line number it was on. The second reason is that I think compiling CSS into the code kind of misses the point of good CSS, which is that you can apply a different style sheet and have an entirely different look and feel with the same markup.

Is there a flag somewhere that I can set to leave the CSS in .css files, where IMO it belongs?

Amy Blankenship
  • 6,485
  • 2
  • 22
  • 45

5 Answers5

8

This is the whole point of encapsulated components.

A component should have it's own styles encapsulated with it so it can be shipped with the styles.

Imagine you want to publish one of your components to be used by others, shouldn't it have its own styles with it ?

That means Angular needs a way to link those css to the component , thus seperates them into chunks and injects them into head tag.

To solve your problem though , you have couple of options :

1- Not using the Emulated Encapsulation :

Components by default have a property called encapsulation which is set to Emulated , you need to change it to None:

@Component({
   encapsulation:ViewEncapsulation.None
})

Then , you can put all you css in the head tag your self like you'd do with a normal html page.

2- If the problem is theme ing , you can make your component themeable .

You can have a theme attribute for your component and then based on that change the styleing :

@Component({
   selector:'my-component',
   styles:[
    `
       :host{
          [theme="blue"]{

              change what ever you want : 

              h1{
                color:blue; 
              }
           }

       }
    `
  ]
})

And then , using this component would be like :

  <my-component [attr.theme]='"blue"'></my-component> // would be blue theme
  <my-component></my-component> // would be default
Milad
  • 27,506
  • 11
  • 76
  • 85
  • 4
    I think the use case where you want a component to always look the same no matter what is far rarer than you want to be able to totally swap out CSS by swapping out the CSS file (which is what CSS does well). I think it's a really weird design decision to prioritize edge cases over real world normal usage. The issue with putting everything in the head tag is that's not going to update based on the styleUrl's specified in the components that are on the screen. If you ever used angular-route-styles in AngularJS, that's closer to what I would expect to happen. – Amy Blankenship Dec 20 '16 at 22:22
  • No sire , the world is going toward components , you really need to google the definition of a component ! I think you want JQuery , not Angular2 – Milad Dec 20 '16 at 22:58
  • 1
    I think Angular 2 won't be useful for much if the only people wanting to use it are developers publishing their components at each other. The CSS Zen Garden philosophy is very widespread, and for a reason. – Amy Blankenship Dec 20 '16 at 23:01
  • BTW, I've already done quite a bit of work with SVG in AngularJS, and I've already come up against how the Shadow DOM makes most real things you'd want to do difficult to impossible. It seems ridiculous to create a framework that makes real work almost impossible, but makes developers feel manly about how encapsulated their components are. – Amy Blankenship Dec 20 '16 at 23:04
  • Alright man , no drama , delete the question and use something else , nothing should force anyone to use a specific framework. – Milad Dec 20 '16 at 23:18
  • 1
    I'm going to accept this answer, as I think it came the closest to a real answer. Others were good and helpful, but I think this one was the most definitive on the "Angular 2 has made some poor design decisions where CSS is concerned, so this is not possible." – Amy Blankenship Dec 21 '16 at 18:23
5

Go to your base Html file(where the root module, main app is injected) and link the CSS stylesheets in your header section.

Webpack will not include it in it's compiled/combined css file which is injected into the page. The css file will still be included at run time in the browser.

<html>

<head>
  <base href="/">
  <meta charset="utf-8">
  <title>dummy</title>
  <meta name="viewport" content="width=device-width">

//was not injected/modified by webpack
  <link rel="apple-touch-icon" sizes="57x57" href="app/images/apple-icon-57x57.png">

//webpack's injected this below from other components's imported/inline css rules
<link href="index-c2cacb5fa3dfbca6116f4e4e63d5c3c7.css" rel="stylesheet"></head>
deek
  • 1,085
  • 1
  • 9
  • 27
  • And how would that work to provide CSS to an individual component? – Amy Blankenship Dec 15 '16 at 23:10
  • the rules will still be valid/work.....but available globally. Not a problem unless your using overlapping names for css classes. – deek Dec 15 '16 at 23:11
  • I think I'd be likely to do exactly that. Coming from the "CSS Zen Garden" school of thought, I don't get the whole philosophy behind CSS in Angular 2. – Amy Blankenship Dec 15 '16 at 23:13
  • It's easy to track down css style sheets of a component....just find what styleUrls point to or add them under styles. As long as you know what component an element belongs too(check tag name), you can pinpoint which css file. BTW, webpack does this, not angular2. Webpack is optional and can be configured to ignore css. – deek Dec 15 '16 at 23:15
  • That's not as easy as having the developer tool list all the properties that are applied to a given html element and list exact line numbers in the exact style sheet that it came from. I'm skeptical that Angular 2 without WebPack dynamically generates a style tag in the say that the old [angular route styles](https://github.com/tennisgent/angular-route-styles) did. I haven't seen any documentation to that effect. – Amy Blankenship Dec 15 '16 at 23:22
  • webpack is just a tool for helping the build process like grunt or gulp. I;m guessing you used a generator like yo to make your project....the default configuration on those generators can be altered. Turn off any UgliyJs or html/css optimizer settings in the webpack config json. Try my way and it should tell you which files and lines just fine....hopefully since webpack will ignore it. – deek Dec 15 '16 at 23:26
  • There's a lot to know about Angular 2, so I guess it's easy to miss something. I couldn't find the exact place in the docs they talk about how this works, but you can see [here](https://github.com/angular/angular-cli/issues/1501) that Angular 2 is reading the CSS to create JavaScript from it. Otherwise, it would just be able to read the URL and create a script tag--it would not need to wait for the contents of the file to return. – Amy Blankenship Dec 15 '16 at 23:52
3

With angular-cli 1.6.5 you can do this:

ng serve --extract-css

You will still have the style-encapsulation features, but devtools will now point to the component css source file.

nilsel
  • 61
  • 1
  • 5
2

I use the angular-cli as well (v1.0.0-beta.22). When I am ready to build for production I run the following command:

ng build -prod -aot

This generates all my production-ready files (bundled, tree-shaken and minified etc). Of particular note is that it will generate two versions of the style sheets.

One in js:

styles.b2328beb0372c051d06d.bundle.js

And another version is plain css:

styles.4cec2bc5d44c66b4929ab2bb9c4d8efa.bundle.css

I run some post-processing on the css file with gulp and use the css version for my production build. I am not sure if the same holds true for lazy loading (where the cli will produced different chunks), but it works for sure when lazy loading is not being used (I haven't launched a production-ready project yet with lazy loading).

I also tried a build with JiT compilation:

ng build -prod

It also produced the raw/minified version of the css style sheet.

Now, I know for sure the folowing does NOT work:

ng build

This will produce all the css embedded within js file, styles.bundle.js.

Since you want to use the raw css file during development, the only workaround I can think of is that you run ng build -prod in order to get the css file. Copy/paste this manually into your assets folder. Run "format" on the file to un-minify the file. Then do a normal build with a modified index.html file referencing your raw css file, and removing the styles.bundle.js script reference. Not pretty, but it might work.

brando
  • 8,215
  • 8
  • 40
  • 59
  • I'm not following how that's going to keep angular from visiting the styleUrl and sucking it in as JavaScript and make it create a style tag instead? – Amy Blankenship Dec 20 '16 at 18:45
  • There is a new version of angular-cli out. It may address this problem: https://github.com/angular/angular-cli/pull/3511 – brando Dec 21 '16 at 17:20
-1
  • Put a wrapper class in html example- <div class="component-1-wrapper"> all yout html here inside component-1-wrapper </div>
  • Structure your sass(scss) in the following way. Since your styles are wrapped inside component-1-wrapper, therefore it will apply only to component-1-wrapperclass .component-1-wrapper{ // all the styles for component-1 here .class-hello{ // styles } }
  • You can compile your css with sass and put all the css(seperated by modules) in seperate folder.Start the filenames by _, sass can import them:

structure

  • You can refer your styles-main.scss in app.ts file @component({ styleUrls:['styles/styles-main.scss']})
  • The style-sheets will be structured this way and individual component's class styles will be applied to particular component since there is a wrapper class in html

Hope it helps!!!!!!

shaunak1111
  • 951
  • 1
  • 11
  • 17