Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using global scss variables in my components styles. #1253

Closed
a5hik opened this issue Jun 30, 2016 · 48 comments
Closed

Using global scss variables in my components styles. #1253

a5hik opened this issue Jun 30, 2016 · 48 comments

Comments

@a5hik
Copy link

a5hik commented Jun 30, 2016

angular-cli: 1.0.0-beta.6
node: 6.2.1
os: darwin x64

Hi I have bootstrap override varaibles.scss, which I want to use as a Global style for my app.

So, I depend on these variables on every component.scss I write. Is there a way I can add a global dependency of variables.scss.

Right now I do import the variables.scss manually in every scss file that require.

@filipesilva
Copy link
Contributor

There isn't any such functionality in the CLI itself, no. There is sass compilation but that's it.

@AmarildoK
Copy link

@a5hik A temp fix for that is to make a _varaibles.scss and import where ever you use your variables. Not the cleanest way.

@pramttl
Copy link

pramttl commented Jul 16, 2016

What @AmarildoK suggested could actually be incorporated as a feature into angular CLI. There could be a shared scss file somewhere and new .scss files in generated components could use have an import line to include the shared scss file by default.

@purushottamjha
Copy link

Yup. Certainly need this feature.

@MateuszG
Copy link

Still nothing?

@mhmo91
Copy link

mhmo91 commented Nov 20, 2016

Any update about this people?

@pquarme
Copy link

pquarme commented Dec 1, 2016

Any update on this?

@jammerware
Copy link

I'm quite new to frontend, but I'm trying to declare some global SCSS vars for my Angular app, and I just want to be sure that it's not intended that what I'm doing should work.

I'm running angular-cli 1.0.0-beta.21. In my angular-cli.json file, in apps[0].styles, I reference my styles.scss file.

styles.scss

@import url('https://fonts.googleapis.com/icon?family=Material+Icons');
@import url('https://fonts.googleapis.com/css?family=Droid+Sans:400,700');
@import '_vars';
@import 'reset';
@import 'global';
@import 'index';

_vars.scss

/* VARIABLES  */
/* brand colors */
$color-accent: #2980b9;
$color-primary: #ecf0f1;
$color-subtle: #aaaaaa;

/* rarity */
$color-rarity-legendary: #4c139d;
$color-rarity-ascended: #fb3e8d;
$color-rarity-exotic: #ffa405;

When I try to reference a variable declared this way in a component's .scss file, the console reports that the variable hasn't been declared.

Is this failing because of something I'm doing wrong, or is this not possible under the current version of the CLI?

Thanks so much for your time and help.

@ahmed-musallam
Copy link

can someone explain to me how the SASS transpiling happens?
I assume this happens:

  1. ng-cli transpiles global sass file to css
  2. find all component specific sass and transpile those to css
  3. concatenate all that css

is that correct?

@greenchapter
Copy link

I have the same problem with global sass variables. Also the transpile is for me at the moment a blackbox

@origin1tech
Copy link

origin1tech commented Feb 3, 2017

What we do is create a folder called shared and under it a styles folder. We then create our sass there. Finally from your top level component typically "app.component.scss" just import.

@import './shared/styles/default';

Forgot you also on the top level component need to set View Encapsulation.

encapsulation: ViewEncapsulation.None

screen shot 2017-02-02 at 5 31 29 pm

screen shot 2017-02-02 at 6 22 00 pm

@ahmed-musallam
Copy link

@greenchapter yeah.. I wish there was some good documentation for it. if you find anything, do let me know.

@origin1tech
Copy link

@ahmed-musallam see my above example I had forgotten the encapsulation flag in the root component. Just remember that the app.component.scss will not be encapsulated so any style imported there will propagate to any child component etc.

In may cases this works just fine, I see little issue with it. you can still have encapsulated styles for components.

@askdesigners
Copy link

Even with the encapsulation set I'm still getting a missing var error on compile. Is there something else that needs to be setup?

@origin1tech
Copy link

@askdesigners hard to say I'd need to see it. The above example I showed works just fine is it possible there's something up with your sass itself? Maybe post some screenshots or something and maybe something will stand out.

@ahmed-musallam
Copy link

@origin1tech @askdesigners you should not disable encapsulation. It's just bad when you have leaking CSS.

If you know SASS, you know that variable and mixin declaration are NOT transpiled to CSS. So there is no issue with doing what @AmarildoK suggested above. just make a variables and mixins partial and include it when you needed. Since vars and mixins do not transpile unless you use them, there is no overhead here whatsoever.

What @a5hik is asking for in the thread is for convenience only... if you use angular, you are already familiar with angular's ceremonial steps for creating components and services.. this is the same thing... Additionally, I dont think the SASS transpiler supports injecting variables on the fly (during transpiling). the only way this can be done is by writing import statement into each sass file before SASS transpiling. And this can be done by a nodejs script if you must have that convenience.

@origin1tech
Copy link

@ahmed-musallam it's only a "leak" if you don't define it.

zero wrong with having a few styles that are global to your app for convenience. If that weren't the case cli wouldn't build with a global styles file pre-config'd nor would encapsulation option be avail. Disabling on a top level component does not negate encapsulation on sub-components.

If it's not what you prefer I understand but to emphatically suggest it's wrong is absurd. It would be unnecessary heavily lifting to have some separate build task/config just for those handful of global styles.

@ahmed-musallam
Copy link

@origin1tech of course! you should use global CSS when you need global styles. Obviously no brainer there. And I would not repeat the same css in every component instead of using a global style.

but what your example, about setting encapsulation: ViewEncapsulation.none does not work as you described it nor was it intended to be used that way. the good folks at rangle.io explain the difference in the three encapsulation methods here: https://angular-2-training-book.rangle.io/handout/advanced-components/view_encapsulation.html. also Pascal Precht has a really good article over at thoughtram.io describing that as well: https://blog.thoughtram.io/angular/2015/06/29/shadow-dom-strategies-in-angular2.html

anyway, we are not talking about "global styles" in this thread, we are talking about "sass variables" and finding a way to reuse them across components.

@AlexBachmann
Copy link

What we do, is that we define a base.sass, that does not generates any CSS but only defines global variables.

This stylesheet is then imported on top of the component sass stylesheets.

@import "./src/assets/private/sass/base";

It does not generate any CSS overhead in the components, you can leave ViewEncapsulation enabled and all is good.

@KTKate
Copy link

KTKate commented Jun 21, 2017

Ahh this is a frustrating problem. I want to just import colors and things one time. Not on every scss file.

@askdesigners
Copy link

I'm so not sold on the encapsulated CSS train. I get the thinking, but honestly if you just write good reusable modular css from the get go it's not a problem at all. It's only an issue when you don't really get the cascade. BEM solves this issue pretty well IMO without any encapsulation at all.

@MickL
Copy link

MickL commented Jul 31, 2017

Yes its kind of frustrating but thats the way scss works. What i don't understand is why component-styles are always inline. If they would be concatenated to global style.scss(before running sass) instead we would have no problems with undefined variables or mixins.

Beneath that there are no sourcemaps at all for the inline styles.

@DD-UX
Copy link

DD-UX commented Aug 11, 2017

I see there is plenty of people having the same issue here. I understand Angular CLI is done the way it is (take it or leave it). But not listening so many people requesting for a more pragmatic way do define the Sass inheritance + stack looks more like a whim rather than a technical issue (should I have to say what CSS means?).

Is quite logic to think a developer would like to handle this in a reusable way avoiding over-importing and taking full advantage of cascading the styles.

Hope Angular CLI team understand this is a constructive critic from someone, like many others, that doesn't see a good reason why don't move forward with such a highly-demanded feature.

@LuckyLam34
Copy link

I'm expecting to see this feature implemented soon. It's so frustrated to write that import statement for every component style.

@MickL
Copy link

MickL commented Oct 16, 2017

How vould this be fixed? The compiler does not include your variables, it just compiles each component-scss seperately. Therefor you need to include your variables/mixins/functions. This is how sass works and writing that import statement is the correct way.

@antoniocastanheira
Copy link

I hope they fix this issue soon. Just in case you need import your sass, Webpack provides a better way to do it:

@import “~variables.scss”;

It's less frustrating than specify the full path.

@cedvdb
Copy link

cedvdb commented Nov 24, 2017

Is there a fix coming or should one use the "work around" described here ?

@aendu
Copy link

aendu commented Nov 27, 2017

There seems to be no 'fix' yet. But in any case, don't use the suggestion with encapsulation: ViewEncapsulation.None unless you really understand its implications.

@amirtoole
Copy link

There is a simple way of achieving this.
Add the following property into .angular-cli.json into "apps":

      "stylePreprocessorOptions": {
        "includePaths": [
          "scss"
        ]
      }

This assumes your scss is in a folder under src called scss.

@gustavossantos
Copy link

@hellofornow, the above did not seem to work for me. Are there any gotchas?

@amirtoole
Copy link

@gustavossantos no gotchas. I can provide some more details though.

src/ 
 scss/
   - variables.scss
 app/
   components/
     - component1.ts
     - component1.html
     - component1.scss
.angular-cli.json

Contents of angular-cli.json are as described above.
Contents of component1.scss would be:

@import 'variables';

...rest of your scss goes here

@AlexHenkel
Copy link

AlexHenkel commented Jan 23, 2018

My two cents:

I've tried CSS native variables and they works well with Angular and SCSS (also for those using Prettier or sth).
Give them a try! They are native, therefore compatible outside SCSS.

https://css-tricks.com/difference-between-types-of-css-variables/

@bentaly
Copy link

bentaly commented Jan 24, 2018

@hellofornow this means each file you'd import a vairables file into each component right? I don't think that's what OP wanted

Right now I do import the variables.scss manually in every scss file that require.

@daniel-seitz
Copy link

@hellofornow what's the benefit for changing the angular-cli.json if I can achieve the same without it and using @import “~variables.scss”;, like @antoniocastanheira wrote?

Also, in general I see no problem implementing something. There might be some implications though, i.e. how are lazy loaded modules handled?

I suggest a discussion on can we do something about it and if, how and which edge cases we need to think about rather than do it now.

@amirtoole
Copy link

@daniel-seitz perhaps a bit of confusion -- this issue is going over many different topics.

Using @import “~variables.scss”; is great if your scss is inside of a folder within node_modules (unmodifiable).

Adding scss paths into angular.cli.json is required if you want "simple" imports for scss that are defined in your project.

Without adding the appropriate scss path(s) into angular.cli.json you will have to do relative path imports.
For example:
@import "./src/assets/private/sass/base"; should be simplified into @import "base";
(assuming you've added the correct entry into .angular.cli.json)

As for automagically importing variables or base into all scss files, that may be a nice feature.
It could be done similar to this comment:
webpack-contrib/sass-loader#218 (comment)

I do think if this feature was added it would need to be a new property of .angular.cli.json.

@daniel-seitz
Copy link

Thank you for the reply @hellofornow. I too would welcome this feature however from my current understanding its not trivial to implement this.

I was not clear enough with my question for you, so one clarification: Look out for the ~ symbol.

If one just imports like this @import “variables.scss”;, then yes this file needs to be inside node_modules - which is bad, don't do this.

BUT! if you do @import “~variables.scss”;, so with a ~, then you can import relative to your src folder. That's it, no other config. (Since we're in the angular-cli repo here I won't go into other structures and what we need to configure that 'home'-path)

Keeping that in mind, what's the need to do this then? I found no documentation.

"stylePreprocessorOptions": {
    "includePaths": [
        "scss"
    ]
}

Then I also did some tests (also with lazy loaded modules, ...) and - as we all know - we would not expect this to happen: Angular CLI with Sass compilation encapsulates the styles so that they won't have effects on other parts of the system.

When using import, we circumvent this and can use all variables, however when mixing variables with real css we also can cascade.

PROBLEM here is that each time use import, that 'real css' gets into the resulting file inline, over and over - which again goes against cascading and worse, makes our dist bigger.

The SOLUTION would be to make the variables (mixins, ...) available to the compilation so that it just knows about them and translating on the fly, nothing else.

I'd like to have these variables, or at least the starting point, in src/styles.scss as it is default but likely needs to be configurable.

If I find the time, I will dig deeper as I know that it's not just us who want this...

@IgorceJovanoski
Copy link

IgorceJovanoski commented May 8, 2018

Am I wrong or AlexHenkel's comment on Jan 23 solves the problem ?

I have my _variables.scss defined

$primary:rgb(211, 14, 127) !default;

So then I can use this variable in a component

.navbar-light .navbar-nav .active a::after {
    border-bottom: 5px solid var(--primary);
  }

.user-view
{
    background-color: var(--primary);
    color: white;
}

To clarify, my styles.scss looks like:

@import 'variables';
@import '../node_modules/bootstrap/scss/bootstrap';

not sure if OP had same problem but works for me, cause I don't have to hard code the default color

@thescientist13
Copy link

Sorry if this is off topic, but per my understanding in this thread, it seems that SASS process files more in isolation, then say LESS did, would that be correct?

In essence, the use case is of being able to use a @mixin which sets some color variables in one file at an "app" level, and hope for that cascade down into all the other components (even if node_modules).

variables.css

$color: 'green';
$theme: 'generic';

@mixin setTheme($theme: 'generic') {
  @if($theme == 'a') {
    $color:  red;
  }

  @if($theme == 'b') {
    $color: blue;
  }
}

app.component.css

@import "~bootstrap/scss/bootstrap.scss";
@import "./styles/variables.scss";

@include setTheme('a');

header.component.css

@import "./styles/variables.scss";

@include setTheme('a');  // only changes red if this is set manually, which is hardcoded and not ideal for a reusable component from npm

h1 {
  color: $color;
}

In this case, anything processed in my app component using $color would change red, but anything in my other components would not change color (would stay the default color of green) unless I manually call setTheme in all my components, which doesn't make them very reusable.

Thanks, and hope that wasn't too confusing! Any thoughts would be greatly appreciated!

@thescientist13
Copy link

I was able to get something working for my use case using sass-vars-loader.

@peterankelein
Copy link

Just an FYI, it looks like using the tilde to reference 'src' from the component level ala @import '~scss/variables'; is buggy (not working) in Angular 6 (issue). @import '~src/scss/variables'; and @import './src/scss/variables'; seem to work, though. Just a PSA if anyone runs into problems.

@rdalfonso
Copy link

I can't believe how difficult Angular makes using SASS. I'm about to switch to React/webpack

@ManuelGraf
Copy link

ManuelGraf commented Feb 27, 2019

this is ONE OF THE MOST COMMON THINGS I CAN IMAGINE. How can you get that wrong?!

also: you can make this work easily via webpack and sass-loader itself. Man it would be great if ng cli offered a way to extend the webpack conf out of the box. Like Vue does.

@MickL
Copy link

MickL commented Feb 27, 2019

Guys this is how sass/scss works and has nothing todo with Angular. Just import your variables and you are good to go OR use a global stylesheets file.

@futbolsalas15
Copy link

So, in conclusion, if you @import something but you doesn't use a var or mixing of that thing you've imported, it isn't included in the final bundle, right?

@cmacdonnacha
Copy link

Is there a way to use sass variables globally without the need to manually import in every single component? Perhaps this would be bad practice anyway as every component then has access, even if t doesn't need it...

@nikhilknoldus
Copy link

Do one thing. It will work.
import variable.scss file in the component where you want to use variables, it will work.
This is not standard, if something standard arrives, it is easily undo-able.

@batousik
Copy link

What if i want separate css bundles, that i can switch at runtime, each bundle using its own _variables.scss?

@angular-automatic-lock-bot
Copy link

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.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Oct 13, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests