Angular-cli: Can't access Sass Global Variables in components scss

Created on 22 Dec 2016  路  29Comments  路  Source: angular/angular-cli

I have a habit of importing my _variables.scss and _mixins.scss into my root src/style.scss file

@import 'styles/base/_variables.scss';
@import 'styles/base/_mixins.scss';
@import 'styles/helpers/flexbox.scss';
* {
    padding: 0;
    margin: 0;
}

body{
    padding: 4%;
    font-family: sans-serif;
}

But when I'm trying to access the variables in my components.scss, it's giving me an error
color: $primary-color;

Isn't there a way I can achieve this simply? Please Help.

Most helpful comment

Seriously there is no better way for this?

All 29 comments

You need to include styles/base/_variables.scss in each and every file where you need to use variables. Same goes for mixins. The actual content of those files will not be included in the final build and wont impact the build size in any way.

For now the solution is as @grizzm0 says.

Dupe-ish of https://github.com/angular/angular-cli/issues/1791, work in progress in https://github.com/angular/angular-cli/pull/2747.

Seriously there is no better way for this?

This is how SCSS has always worked. It really has nothing to do with the Angular CLI. The component's CSS is being compiled by itself - the other files aren't there. There's no reason for them to be there.

This is not only how it works, this is how you should WANT it to work. You don't want coupling with monolithic styles. You WANT each component to be a COMPONENT. They are isolated, encapsulated pieces of logic.

Add this to .angular-cli.sjon (change includePath to your path):

"stylePreprocessorOptions": {
        "includePaths": [
          "../node_modules/bootstrap/scss/"
        ]
      },

@JustasKuizinas if you want you can:

  • Ditch SASS and use css vars.
  • write a service that create css variables in style element in the head.
  • Get variables for the head style service from a js config
  • reuse same ts config in your template / ts code

  • When building your project with webpack use pure css with autoprefixer
    or

  • use the same approach as mentioned above with no variables for color / sizes configured if you van the benifits of the pre processor

More on this here:
https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables

As mentioned above this is not an angular issue but more of a seed (project base that use angular) issue (with all the build processes and pre-processing pre-dictated by the author).

Looks like we just need to duplicate in every component.

@import "~style/variables";

@AlexanderKozhevin Exactly. Just like you need to import anything you use in typescript you also need to import anything you use in SCSS.

I can make another recommendation on this.

I am buzzy building a framework that will have no classes, only placeholders, mixins and variables. You can import this in the tag and write your sass as per usual but for the component.

My afore mentioned solution has some problems, for example css has not loops and ifs. Therefore it is better to just use sass.

You can then import base styles like import grid or responsive-grid in you app component (root component).

Well, there is this loader that could resolve all our problems - https://github.com/shakacode/sass-resources-loader
I've been using it in one of the ejected projects, but will be nice if we could do this directly from CLI.

@GuskiS Yep, sass resources loader is great, but out of the box ng cli karma config will fail with it. SASS vars will not get picked up, but during a build and development it will work.

...Currently trying to figure out to get my tests to pass with it 馃

@GuskiS that looks like the best option, combining that with importing sass modules using angular's styleUrls: [] has turned out to be my solution to the problem.

Again, as always, setup usually depends on your project.

My current solution is to turn off ViewEncapsulation for the component, but I dont like this at all. I wish there was a clean solution for this.

@Component({
selector: 'app-admin',
templateUrl: './admin.component.html',
encapsulation: ViewEncapsulation.None,
styleUrls: ['./admin.component.scss']
})

@aoakeson, form my understanding, that is based on experience and not the actual algorithm, view encapsulation only applies when styling is applied to a class specific to that component. I haven't had to turn on viewEncapsulation for any of my component. The global stylesheets just seem to apply.

I am curious to know why this is different for you.

@dewwwald I think I figured out my problem. It turns out the elements that I was trying to access using these global variables were outside the scope of the main angular app. As my app is comprised of multiple modules, and apps it was not able to access these. I moved things around and am now able to have my components keep ViewEncapsulation on.

@grizzm0:

You need to include styles/base/_variables.scss in each and every file where you need to use variables.

@AlexanderKozhevin

Looks like we just need to duplicate in every component.

You should never do this because https://github.com/angular/angular-cli/issues/8431 :( Thus component.scss is totally unusable in real projects now...

@LastDragon-ru As explained in that issue you should never import files that actually render CSS more than once. You can import files that contain variables and mixins as many times as you want as they do not affect the output.

@grizzm0, For example with bootstrap sometimes more simply and better to use something like &.disabled {@extend .form-control:disabled;} or @extend .is-valid than redefine(copy) this styles. because after copying we will need to check it after each bootstrap update :( So this feature/issue can be useful.

I prefer creating index.scss in the components folder (lets say you have a folder Search that lives under components). Then, import all the .scss files used in this folder into your newly created index.scss. Then, include @import "../components/Search/index"; in App.scss or wherever all your global partials are stored. Now all the .scss files inside components/Search will have access to global variables.

@kkuzmina I know that it`s not right thing to do, but helped me as well 馃憤

This is how SCSS has always worked. It really has nothing to do with the Angular CLI. The component's CSS is being compiled by itself - the other files aren't there. There's no reason for them to be there.

This is not only how it works, this is how you should WANT it to work. You don't want coupling with monolithic styles. You WANT each component to be a COMPONENT. They are isolated, encapsulated pieces of logic.

how does importing a static path fit to that cool isolation idea of yours? I call BS. Duplication of declarations is what really sucks. Thats why there are things like tree-shaking and module systems. But its not like i can create style modules (singletons) in angular which I can inject somewhere.

This is how SCSS has always worked. It really has nothing to do with the Angular CLI. The component's CSS is being compiled by itself - the other files aren't there. There's no reason for them to be there.
This is not only how it works, this is how you should WANT it to work. You don't want coupling with monolithic styles. You WANT each component to be a COMPONENT. They are isolated, encapsulated pieces of logic.

how does importing a static path fit to that cool isolation idea of yours? I call BS. Duplication of declarations is what really sucks. Thats why there are things like tree-shaking and module systems. But its not like i can create style modules (singletons) in angular which I can inject somewhere.

If you need to use a variable you need to import the file the variable is declared in. A variables file does not produce any output while imported and wont affect the build size.

For the variables to work application wide angular would have to include your global application SCSS in each component SCSS which would produce duplicated CSS.

If you import the variables file where you need it each component will have it's own "isolated" CSS while it actually "borrows" variables from a shared SCSS file. Just as you would do with a shared module in typescript/angular.

This way there's no need to declare the variable multiple times. But if you want to you could skip the import and redeclare the same variable over and over again, which seems a bit annoying to me.

Does that also hold for mixins and placeholders?
I actually had the same issue with Vue CLI and fxed it by using webpack loader oprions.

    loaderOptions: {
      sass: {
        data: `
          @import "@/assets/styles/vars.scss";
          @import "@/assets/styles/mixins.scss";
        `
      }
    }

I personally don't like scoped css (which Vue OFFERS and doesnt REQUIRE), I also don't really care that i have to import my mixins, vars, placeholders etc. I just want to be sure none of those will be printed (multiple times) in my final output.

@ManuelGraf only css classes, id's and statements get printed in the final result. Mixins are reuse-able statements that print nothing until they are used. Same holds for placeholders, mixins and scss vars.

@ManuelGraf Variables nor mixins produces any output while imported. Comments in those files will (the last time I checked) however be printed multiple times. But the CLI should strip all comments when building anyhow.

Okay I am going to use it as proposed. But for some reason the ~/... doesnt work for me. What is ~ exactly in a multi-project angular 7 CLI environment?

@ManuelGraf try this: @import ~src/variables in component.scss.

This topic has been over explained, no one reads the thread before posting. Could we lock the topic?

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings