Accessing bootstrap scss variables in angular 2 component
Asked Answered
C

3

24

I'm working on a new Angular2 project built using Angular CLI and have configured the project to use SCSS. I have Bootstrap 4 successfully loaded into my styles.scss file however if I try and access any of Bootstrap's (or my own variables defined in styles.scss from within a component I get Undefined Variable build error.

Are the style files for components compiled before the main entry in the styles node of angular-cli.json? How can I make is so that any variables defined at that global level are available to all components in the application? Thanks!

angular-cli.json

"apps": [
  {
    ...
    "styles": [
      "styles/styles.scss"
    ],
    ...
  }
]

styles.scss

// Bootstrap
$enable-flex: true; // Enable Flexbox mode
@import "../../node_modules/bootstrap/scss/bootstrap";

component

.navbar {
  background: $brand-primary; // Undefined variable here
}
Cerebroside answered 16/10, 2016 at 11:41 Comment(0)
P
39

Just because you are importing the bootstrap 4 into your styles.scss doesn't mean your .scss files on your components have access to that.

On your component.scss you have to import the Bootstrap variables:

@import '~bootstrap/scss/_variables.scss';

.navbar {
  background: $brand-primary; // No more Undefined variable here
}

Explanation

A lot of people seem to me confused by this, you should not import bootstrap.scss to your components you should only import the things that you need.

If you look closely into the source code of bootstrap.scss they have everything separated in different files. You have the mixins folder and the _variables.scss file. Those should be the only things you import on your component to avoid CSS duplication.

Would this increase my bundle size, importing these things on every component?

No, it won't. Why? mixins and variables are sass specific (at least for now) so when you import all the variables into your component like this:

@import '~bootstrap/scss/_variables.scss';

.navbar {
  background: $brand-primary;
}

the output CSS of that will be:

.navbar {
  background: #007bff;
}

The rest of the variables will be discarded after compiling to CSS.

Pinchas answered 16/10, 2016 at 13:6 Comment(5)
If I have a dozen components, won't the _variables.scss file be read a dozen times?Jihad
Yes it will be read, but not included in the code, remember that css doesn't have variablesPinchas
What's with the ~ tilde character? Is that how you reference [/*/**]/node_modules/{{packageName}} in SCSS? Similar to @angular/core/... in TS?Trager
Yes, exactly that, except the TS part, you don't need a @ to reference a package from the node modules. In TS and node any absolute imports will resolve to node_modulesPinchas
@FabioAntunes css have variables :)Clark
T
5

Create a _colors.scss file, copy all the color variables inside and import that file in your component.scss file.

Terylene answered 16/10, 2016 at 11:48 Comment(0)
S
4

A few people have suggested @import-ing the variables.scss in every component .scss but I found this a little messy. Doing so did not also work well with the way our company CSS is architectured. I ended up going in this direction to enable me to use the variables, mixins, and also extend styles. This also allows me to manage all of the CSS in one location.

I'm currently working on a project that has been generated by Angular2 CLI. So there is a main style.scss


Another way I was able to accomplish this is by doing the following:

  1. Removing the styleUrls from the app.component.ts files.

    @Component({
        selector: 'app-root',
        templateUrl: './app.component.html'
        // styleUrls: ['./app.component.scss']
    });
    
  2. I manage all the less files in the main styles.scss. So my current setup looks something like:

    // Bootstrap
    @import "../node_modules/bootstrap-less/bootstrap/index";
    
    // Company Branding
    @import "theme/index";
    
    // Components
    @import "app/app.component.scss";
    @import "app/search/search.component.scss";
    

Hopefully this alternative solution will be helpful to someone.

Specht answered 3/11, 2016 at 20:52 Comment(5)
This should work, but this way you are probably not able to leverage view-encapsulation. I suppose you have to change your components to encapsulation: ViewEncapsulation.None. Am I wrong?Ministrant
@Ministrant yeah that will not work. I use encapsulation differently. In our coding style we always have a selector that differentiates the pages. Instead of using encapsulation we just use the specific selector for that page.Specht
A quick test revealed: Duplicate imports apparently do not impact filesize. Just checked this with a couple of components and the effective file size remained the same whether I would include _variable.scss in every single component or not (I did not check the docs or even the implementation though). So @fabio-antunes 's answer is probably better for it doesn't break encapsulation.Devoice
But if you import whole bootstrap.scss into each component scss file, then the main.bundle.js blow out of proportion for each component create a bunch of component related definitions.Bald
@IgorBabic why would you import the whole bootrap.scss to your components when you only want the the variables or mixins? You should only import what you need.Pinchas

© 2022 - 2024 — McMap. All rights reserved.