48

I created a global style sheet using Sass and put it in the public/style/styles.scss. I only specify a background color.

In the index, I added a link to it: <link rel="stylesheet" href="style/styles.css">

The background color does not work on the body tag. Upon inspecting the body tag I can see that the background-color was applied but overruled by scaffolding.less:31

What I am doing wrong?

Joundill
  • 6,828
  • 12
  • 36
  • 50
Thibs
  • 8,058
  • 13
  • 54
  • 85

14 Answers14

46

As of the beta.14 release of the CLI (which uses Angular 2.0 final), a global stylesheet can be linked inside angular-cli.json under the "styles" key. This is a reference to a file relative to the src/ directory, which is style.css by default.

Leveraging this method you could:

  • Copy the global styles into src/styles.css
  • Use CSS imports to import external rules into styles.css
  • Add more global styles via the apps[0].styles property in angular-cli.json

See also Global Styles in angular-cli's wiki.

filoxo
  • 8,132
  • 3
  • 33
  • 38
  • works! and you don't need to add in the index.html file, once you add in the angular-cli.json – Salvatore Pannozzo Capodiferro Oct 26 '16 at 17:48
  • 4
    Are there any pro/cons to using CSS imports to import into `styles.css` vs. just adding them to the `styles` property of `.angular-cli.json`? – WillyC Apr 05 '17 at 17:58
  • 1
    @WillyC interesting question. I setup a brand new project using the current version of the CLI (v1.0.0) and tested both methods. The output is exactly the same, even the hash. The only recommendation I'd make is to import app styles in `styles.css`, while third-party styles (eg. Bootstrap) would be better defined in `.angular-cli.json`. – filoxo Apr 09 '17 at 02:07
  • @WillyC why do you recommend to include third-party styles in `.angular-cli.json`? Importing inside styles.[s]css has the following advantages in my opinion: - it feels more natural and canonical way of doing it. - it's less cli-dependent and more general. - it doesn't require you to restart `ng serve` So unless you want to use extra options of `styles[]`, (e.g. `async`), I'm with importing inside styles.[s]css – Alireza Mirian Jun 06 '17 at 18:41
  • @AlirezaMirian I didn't recommend doing that at all - I just asked a question if there were any pros/cons to doing so. You have contributed to answering that, so thank you. It was filoxo who made the recommendation, and I think they were just making that recommendation out of a means of separating the sources of CSS files. I have no real opinion on it either way, I was just interested to hear the opinions of others. – WillyC Jun 06 '17 at 18:46
  • @WillyC oops, wrong mention, sorry. Yes, I also was looking for `import` vs `styles[]` reached here :) – Alireza Mirian Jun 06 '17 at 18:49
  • @filoxo https://stackoverflow.com/questions/37484937/angular-cli-how-to-add-global-styles/39622583?noredirect=1#comment75794797_39622583 – Alireza Mirian Jun 06 '17 at 18:50
  • another advantage of import is better path autocompletion by IDE – Alireza Mirian Jun 06 '17 at 18:51
  • 2
    @AlirezaMirian To add more clarity, I'd recommend `styles[]` to import styles that you wouldn't want to transform/preprocess (eg. Bootstrap), just include them for global use. Use `imports` if you want to actually put those styles though your build pipeline (eg. normalize.css or a module that exposes some variables that you'd actually want to rely on). I don't think I'd care for path autocompletion for styles... – filoxo Jun 06 '17 at 19:31
  • @filoxo what about non-cli angular project? how should global styles be used? – ANewGuyInTown May 16 '19 at 09:20
19

Sounds like a CSS selectivity conflict between your linked CSS file and the compiled CSS in JavaScript that Angular places as Embedded CSS in the head or your web page, but which is stored in the memory of the browser.

This is why I always recommend you stop using Angular's poorly designed embedded CSS system and use linked CSS only. To do that you need to change your Angular JSON Setting file to remove the Embedded Style sheet, then Add a Setting to Tell Angular to copy your Linked CSS to the "dist" folder so your HTML link can access it. But see below for details...it helps to understand how CSS works in Angular. It is NOT intuitive!

HOW CSS WORKS IN GOOGLE ANGULAR

For starters, none of the above answers explains what is REALLY going on in Angular's CSS system or why you might be seeing cascading problems. In an Angular project, when you add styles paths directly into the "angular.json"(newer) or "angular-cli.json"(older) settings file, Angular grabs all those CSS files, compiles them into a JavaScript file, then spits them out as embedded styles in the head of your HTML file:

This angular.json setting:

  "styles": [
    "src/styles.css",
  ],

Gets turned into HTML and added to a gigantic embedded <style> tag that JavaScript creates in the DOM of your browser:

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Project</title>

<style>
  .mystyle {background:blue;}/* everything in styles.css gets dumped in here! */
</style>

<body>
...

Bad CSS design! You can only see this if you go to a browser and use F12 and look at the actual DOM and CSS angular spits out in memory in your browser. If you use component styling, the same thing happens when those components get loaded into the DOM by Angular modules, etc. They get dumped into ANOTHER embedded style element under the first one.

I'm not 100% sure the Angular guys understood what they were doing adding embedded styles like this. Any CSS in your linked styles could be hidden with these embedded style systems Angular uses if they are inserted AFTER your linked styles.

One of the things I don't like about Angular is if you place CSS IMPORT tags inside your "styles.css" file (for example to bootstrap), the compiler also grabs those and spits those out into these embedded style tags, as well. Traditionally, importing one style sheet into another was used to control cascade order as imported sheets were inserted before other styles in the parents page. We use @import to hide styles that are not supported in very old browsers, and manage large libraries of styles by function this way. Because Angular ignores all that now and jumbles all this CSS together, you're left with a gigantic embedded inline style block in the head of your "index.html" file, and its very difficult to control cascading orders this way.

Angular's style system also doesn't support skinning of websites or themes using this inline system, nor global caching of linked styles between pages which would save bandwidth. And it doesn't matter WHERE you put your style sheets in your folder structure, as people above mention. If they are referenced in the angular.json, they all get compiled into these embedded style blobs at the head of your page in an order you cannot control.

For that reason, I recommend you REMOVE ALL STYLE REFERENCES FROM "ANGULAR.JSON"! Then add them back into your "index.html" manually as links like this:

<link href="styles/styles.css" rel="stylesheet" />

...then changing your angular.json settings file by removing the styles entry in your styles array path list then pasting it back into your assets array list so Angular knows where to migrate your CSS folders and files in the dist folder, like so:

        "assets": [
          "src/styles",
        ],
        "styles": [
        ],

When you now compile your Angular application, JavaScript ignores your CSS file (in terms of compiling it with the JavaScript and later building it into a <style> CSS block) and instead pushes that file as a plain vanilla resource CSS file into your "dist" folder of files. When you push that to production, your <link> CSS tag can now send that CSS file to the user's browser, which is normally how most websites deliver CSS in websites today.

Your Angular application is now using just <link> or external CSS files for styles in your index.html file rather than <styles> or embedded CSS. You can still use this internal or "embedded" Angular-managed CSS system. I am not 100% against it. In rare cases, embedded CSS was great for supporting offline web pages. Angular has a nice system for controlling and manipulating CSS this way. But it is just not traditionally how CSS was used in most caching systems the past 20 years. Using "external" or <link> CSS, your main styles are now stored in the user's "native" browser cache for much longer periods of time, saving bandwidth and rendering/paint speed in the browser.

<link> CSS gives you back complete control of your websites styling, cross-browser fixes, skins, etc. Your front-end designers also have control over it and updates are independent of kooky polyfills, preprocessing, scripting dependencies, etc. You also now gain back full control of your cascade order, which is critical if you want full control over that.

Linking external styles also has huge caching advantages over Google Angular's broken CSS system, as the browser's naturally cache all this on page refreshes or revisits. We've been using CSS this way since the 1990's so Im baffled why Google went back to an old inline style system. Linked styles are just superior for managing and caching css. We also add versioning query strings to the end of linked CSS files (/mystyles.css?v=1.2) so you can force refreshes, etc. Again to do this, REMOVE all references to CSS in the angular.json file and manually add them in as links in the head of your index.html file.

I do think you can safely use the Angular's modular or component-based styling system as long as you understand that when you lazy load or preload Angular modules those embedded style elements do get pushed down from the server to the user on every new visit or refresh of the script block. Also understand that way modern browsers work today is not how older ones worked.....new browsers do not parse embedded styles after linked ones, but honor the order you inserted them into the head of your HTML page. In other words today, the order you put them in the page could be unpredictable in Angular when it finally delivers the HTML. Cascade order is today now heavily controlled by the HTML designer, not the W3C recommendations.

I think that's the main purpose of Angular's modular styling system....to take over control of CSS away from the designer and hope they don't notice. But to be honest, its unnecessary if you use external sheets and follow basic cascading rules.

Stokely
  • 12,444
  • 2
  • 35
  • 23
  • AWESOME -- searched for this common sense explanation for weeks and months. I would BOLD the "then pasting it back" as I glanced over this until I re-read the post. – mobibob Jul 08 '20 at 00:08
  • 2
    The Angular way is simple: inline styles are so much faster than referencing an external file even if this file is in the same project/repository. Also on production, you want your app to be as fast as possible and the code to be as minified as possible to reduce the loading time: external files not always are minified. I don't believe in your solution at all. – Ferie Oct 16 '20 at 16:45
  • Ferie I disagree. Linked CSS gets loaded very quickly as its just a few kilobytes compared to megabytes of ECMAScript your shove into the user's cache (that contains the CSS in Angular). Linked CSS also is loaded first, so is cached when the DOM comes online. Its also preserved for all future updates of your site in the user's browser cache. Its also easier to maintain and control, and prevents cascading issues. You can also control CSS for older browsers using import back to Netscape. Anyone using inline or embedded CSS is using antiquated technology deprecated by most designers 15 years ago. – Stokely Oct 22 '20 at 01:08
  • 1
    So much of what you said is wrong. For one thing, using Angular's method, the CSS is still cached. But instead of caching it in a CSS file, it gets cached in Angular's JS file. This lets Angular figure out which CSS is relevant, and add it to the DOM on an as-needed basis in order to minimize loading and rendering times. – Eliezer Berlin Feb 14 '21 at 14:57
  • 1
    `if you place CSS IMPORT tags inside your "styles.css" file, the compiler also grabs those and spits those out into these embedded style tags, as well.` This is a very, very good performance feature of Angular. The reason why is that if you put an `@import` in a normal CSS file, the entire page loads slower because the browser can't even **START** downloading the second @imported file until it 100% finishes downloading and parsing the original CSS file and discovers there's a another file it needs to download. Therefore it can't download both CSS files simultaneously, and it renders slower. – Eliezer Berlin Feb 14 '21 at 15:06
  • 1
    Eliezer, its not truly "cached" in the browser, however, as any refresh of the script forces another giant megabyte download of all the CSS embedded in your script again. Google Angular is blocking the native browser's ability to cache CSS in linked elements used by thousands of page views your script is manipulating in the DOM. The purpose of using linked CSS is to download styles ONE TIME to the user and never again unless forced to. Angular breaks that model. And using "import" as a circus trick here fails as a older browsers use "import" in different formats and we use it to block IE1-7. – Stokely Mar 12 '21 at 21:06
  • Thank you. This explanation from you, helped me —> REMOVE ALL STYLE REFERENCES FROM "ANGULAR.JSON"! Then add them back into your "index.html" manually as links like this: – Mm Victory Oct 20 '21 at 13:59
  • Import calls inside a linked or inline style tag all download in parallel to each other over a shared connection. Just make sure you do not mix import with additional CSS in the file. Multiple import calls are only blocked in one case in old Internet Explorer when you have external sheets with imports competing with sheets. Then there is a wait. In addition, using new HTTP2 multiplexed servers , they now manage multiple calls over the same connection. So, the idea CSS import calls block anything or needs minimization is a myth. – Stokely Jul 23 '22 at 14:12
  • This is simply misleading: `Angular grabs all those CSS files, compiles them into a JavaScript file, then spits them out as embedded styles in the head of your HTML file:` It will do this for SSR for performance reasons but not just for everything always. I personally don't use SSR (server side rendering) but I still see this behavior for classes / elements in my index.html file (I have a loader graphic with .loader class and it pulls that and embeds it). So there's more to it than 'put your styles.css manually into index.html'. People's needs vary a lot but be careful without more context. – Simon_Weaver Feb 22 '23 at 18:49
  • By default Angular injects the `styles.css` into the index.html (although it may inject into the head too for SSR). If you're not seeing that behavior perhaps you have `inject: false` in the styles config https://angular.io/guide/workspace-config#styles-and-scripts-configuration – Simon_Weaver Feb 22 '23 at 20:52
9

Sep 2019:

Most other posts are old.

File: \angular.json
Key : projects > myProjectNameHere > architect > build > styles

"styles": [
    "src/styles.css",
    "node_modules/font-awesome/css/font-awesome.css",
    {
        "input": "./node_modules/bootstrap/dist/css/bootstrap.css"
    }
],

File: src/styles.css

/* You can add global styles to this file, and also import other style files */
/* That is, have put css that is common for all pages in this file.  */

body {
  font-family: "Ubuntu", sans-serif;
}

With above two things, the css is applying fine to all pages.

So, nothing new to be done if you have Angular 8 or above.
If you have an issue, then you only need to clear cache (or, do Ctrl + Shift + R )

Manohar Reddy Poreddy
  • 25,399
  • 9
  • 157
  • 140
7

There is also a solution to add external CSS, which is, Put all your CSS in assets/css folder like this:

assets/css/style1.css
assets/css/style2.css
assets/css/style3.css

AFter adding all external CSS, you have to import their reference in global style.css (i.e src/style.css) like this:

@import 'assets/css/style1.css';
@import 'assets/css/style2.css';
@import 'assets/css/style3.css';

Also don't forget to include global CSS in angular-cli.json like this:

  "styles": [
    "styles.css",
  ],
ARKhan
  • 1,724
  • 22
  • 30
5

I know this is too late, but as things keep changing. As of March 16, 2017

this worked for me for the cli.

<link rel="stylesheet" href="src/styles.css">
Nikhil Das Nomula
  • 1,863
  • 5
  • 31
  • 50
4

While I think @filoxo's answer is the documented solution, something like the following works for me as well, and might make it more clear which component needs it:

require('style!../../../node_modules/bootstrap/scss/bootstrap-reboot.scss');

Or when using more recent versions of Angular CLI:

require('style-loader!../../../node_modules/bootstrap/scss/bootstrap-reboot.scss');

Or:

@Component({
    selector: 'my-component',
    styles: [require('style-loader!../../../node_modules/bootstrap/scss/bootstrap-reboot.scss')],
    styleUrls: ['./my.component.scss']
})

The latter might not be allowed; maybe one should not provide both styles and styleUrls, as I'm getting "An object literal cannot have multiple properties with the same name in strict mode" and "Duplicate identifier 'styles'".

Community
  • 1
  • 1
Arjan
  • 22,808
  • 11
  • 61
  • 71
  • Still investigating: maybe one should not provide both `styles` and `styleUrls`, as I'm getting "An object literal cannot have multiple properties with the same name in strict mode" and "Duplicate identifier 'styles'". – Arjan Dec 18 '16 at 14:33
  • ...also, some claim this does not work with AOT, but for me it does (when using `ng build --aot`). – Arjan Jan 29 '17 at 01:02
2

I had the same problem and found this example from before there was even sass/less support in the cli. I suppose the current build of the cli (1.0.0-beta.5) may only compile component level sass, and may even ignore .css in the /src folder. I managed to put global *.css in the public/ folder and have it copied over to /dist, but couldn't get the same behavior from /src and preprocessors didn't seem to compile by default. I suppose that may be by design and IMHO somewhat counterintuitive. Angular cli is luckily built on top of Broccoli and it may be well worth the time and effort to learn how to customize the build using Broccoli like in the example below:

Here is a copy of the angular-cli-build.js I ended up with.

'use strict';
/* global require, module */

var Angular2App = require('angular-cli/lib/broccoli/angular2-app');
var compileSass = require('broccoli-sass');
var mergeTrees = require('broccoli-merge-trees');
var _ = require('lodash');
var glob = require('glob');

module.exports = function(defaults) {

  let sourceDir = 'src';
  let app = new Angular2App(defaults, {
      sourceDir: sourceDir,
      sassCompiler: {
        includePaths: [
          'src/style'
        ]
      },
      vendorNpmFiles: [
        'systemjs/dist/system-polyfills.js',
        'systemjs/dist/system.src.js',
        'zone.js/dist/*.js',
        'es6-shim/es6-shim.js',
        'reflect-metadata/*.js',
        'rxjs/**/*.js',
        '@angular/**/*.js'
      ]
    });
    let styles = mergeTrees(_.map(glob.sync('src/**/*.scss'), function(sassFile) {
        sassFile = sassFile.replace('src/', '');
        return compileSass(['src'], sassFile, sassFile.replace(/.scss$/, '.css'));
    }));
    return mergeTrees([app, styles], { overwrite: true });
};
2

hi in angular 4we can add our Global styles in styles.css which is referenced in angular-cli.json

 "prefix": "app",
      "styles": [
        "styles.css"
      ],
      "scripts": [],

we can import all our css to styles.css file

/* You can add global styles to this file, and also import other style files */
@import '~@angular/material/prebuilt-themes/indigo-pink.css';
@import 'assets/css/test.css';
Lijo
  • 6,498
  • 5
  • 49
  • 60
1

just rename src/styles.css to src/styles.scss

remember to rename styles.css to styles.scss in the .angular-cli.json too.

Rusty Rob
  • 16,489
  • 8
  • 100
  • 116
0

I've been using the following strategy (though I haven't seen any official solutions on this from the angular-cli team, so there may be a better method out there):

If all of my src files are in src/app/..., I place an app.scss file in the root ./app directory. That then gets compiled to css automatically with the current build configuration, so I can include it in my index.html as such:

<link rel="stylesheet" type="text/css" href="app/app.css">

If your file structure is different for whatever reason from the default CLI file structure, just make sure the app.scss file is included in the same directory where your main app component lives. I like this technique because it means I don't have to alter the build, making it less painful to update the project in the future.

  • This works for now until we hear back from angular-cli team I'll use this as I don't need to modify any settings. – Thibs Jun 08 '16 at 14:22
0

For elements outside of the scope of your application's <app-root> (e.x. <body>) you can use the solution other's provided.

If the element is inside your application, you could also not make it global and instead define the styles in a string, then import it into the styles property on the Component class decorator where you want to use those styles.

That way you will get encapsulation and re-use. It just comes with the downside of writing it in a string which may limit your editor's capacity to offer static analysis of your styles.

AFAIK, the angular cli will not compile it twice.

Example:

const tableStyles = `
    table { color: red; }
`;
@Component({
    selector: 'app-overview',
    templateUrl: './overview.component.html',
    styleUrls: ['./overview.component.scss'],
    styles: [tableStyles] // <- here
})
export class OverviewComponent { ... }

And if you want to have the styles in a proper file, you can apply the same logic to the styleUrls property.

Example:

@Component({
    selector: 'app-overview',
    templateUrl: './overview.component.html',
    styleUrls: [
        './overview.component.scss', 
        '../common/table-styles.scss' // <- here
    ]
})
export class OverviewComponent { ... }
Kevin Beal
  • 10,500
  • 12
  • 66
  • 92
0

I am using Angular v8.1.2 with SCSS as the style format, and found the global syles.scss is not working.

In angular.json, it is:

    "styles": [
      "src/styles.scss",
      "node_modules/bootstrap/dist/css/bootstrap.min.css"
    ],
    "scripts": [
      "node_modules/jquery/dist/jquery.min.js",
      "node_modules/bootstrap/dist/js/bootstrap.min.js"
    ]

After google search, I found the reason from https://github.com/angular/angular-cli/issues/10855:

The issue only reproduces if we have more than one non-empty file in projects.architect.build.options.styles setting of angular.json.

My solution: Remove the "node_modules/bootstrap/dist/css/bootstrap.min.css" entry from the styles array, leaving "src/styles.scss" as the only file in the [ ], and then open the styles.scss, and adding the following line at the top of the content:

@import "node_modules/bootstrap/dist/css/bootstrap.min";
wcb1
  • 665
  • 1
  • 7
  • 6
0

Depending on the use-case, it could be a good idea to use "ViewEncapsulation". This also can remove shadow dom from your HTML elements.

@Component({
   selector: '...',
   templateUrl: '...',
   styleUrls: ['...'],
   encapsulation: ViewEncapsulation.None
})

Don't forget to import { ViewEncapsulation } from '@angular/core'. For more info see: https://angular.io/guide/view-encapsulation

-1

Add scss to styles array of angular-cli.json.

  • 2
    Hello and welcome to Stack Overflow! Thanks for leaving an answer but can you further explain, for any interested people, how they might do what you're suggesting? – Regular Jo Mar 04 '17 at 03:38