Bootstrap SASS Variable Override Challenge

Bootstrap SASS variable override challenge

Solved, but I don’t know from which version this works. I believe the solution could have always been available. Tested on:

> sassc --version

sassc: 3.2.1
libsass: 3.2.5
sass2scss: 1.0.3

We are going to use a simplified environment, so filenames do not match with Bootstrap’s.


Challenge

Given a framework we do not control (for example installed only on the Continuous Integration environment and not available in our machines) that expresses SCSS variables in the following manner:

// bootstrap/_variables.scss

$brand-primary: #f00 !default;
$brand-warning: #f50 !default;

$link-color: $brand-primary !default;

And given a file in that same framework that uses the variables:

// bootstrap/main.scss

a:link, a:visited {
color: $link-color;
}

The challenge is:

Include the framework in your own application’s SCSS in such a way that

  1. variables’ dependencies in the framework are preserved and honors;
  2. you can depend in on the default values but still be able to change the results on the framework dependencies.

More precisely:

Include the framework in your application’s SCSS in such a way that $brand-color will always be the inverse of $brand-warning, whatever its value is in the framework.

Solution

The main file would look like this:

// application.scss

@import "variables";
@import "bootstrap/variables";
@import "bootstrap/main";

And your variables file would look like this:

// _variables.scss

%scope {
@import "bootstrap/variables";

$brand-primary: invert($brand-warning) !global;
}

Results:

> sassc main.scss

a {
color: blue; }

Explanation

The %scope part is not something magic of SCSS, it’s simply a hidden class with the name scope, available exclusively for later extensions with @extend. We are using it just to create a variable scope (hence the name).

Inside the scope we @import the framework’s variables. Because at this moment there’s no value for each variable every variable is created and assigned its !default value.

But here’s the gimmick. The variables are not global, but local. We can access them but they are not going to pollute the global scope, the one that will be later used to derive variables inside the framework.

In fact, when we want to define our variables, we want them global, and indeed we use the !global keyword to signal SCSS to store them in the global scope.


Caveats

There’s one major caveat: you cannot use your own variables while you define them.

That means that in this file

%scope {
@import "bootstrap/variables";

$brand-primary: black !global;

@debug $brand-primary;
}

The @debug statement will print the default value defined in bootstrap/_variables.scss, not black.

Solution

Split variables in two parts:

%scope {
@import "bootstrap/variables";

$brand-primary: black !global;

@debug $brand-primary;
}

@debug $brand-primary;

The second @debug will indeed correctly print black.

Using bootstrap sass, some variables are not being overridden

You are using the well class on the element you want to see in green instead of gray.

But the default color for well is defined as:

$well-bg:                     #f5f5f5 !default;
$well-border: darken($well-bg, 7%) !default;

So if you want to change the color of the well, you should change the color of $well-bg. If you want to see for what elements the $gray-base color is used, search for $gray in this file.

Edit by OP

Note that the names of the variables that you are looking to override are found in the file: _bootstrap-variables.scss.

If you're pulling in bootstrap-sass via npm (which I'm doing in this project) that file can be found at

node_modules/bootstrap-sass/templates/project/_bootstrap-variables.scss

Can you override a sass variable twice, dependant on context?

Yes you can achieve this see the example below

$primary-color: red;

body {
background-color: $primary-color; // here red color will get applied.
}

.myClass {
$primary-color green;
background-color: $primary-color; // here the green color will get applied
}

You can override the value of variable inside a scope.

Override a component's default sass variables in a different angular-cli project

Hi to edit component from node_modules, just import it and put in .angular-cli.json.

For example, suppose you want to modify bootstrap 4 variables.

1. Create new file src/assets/bootstrap/index.scss:

@import "node_modules/bootstrap/scss/functions";
@import "node_modules/bootstrap/scss/variables";
@import "variables";
@import "node_modules/bootstrap/scss/mixins";
@import "node_modules/bootstrap/scss/root";
...

this is only copy all file scss from bootstrap.

2. Create _variable.scss in src/assets/bootstrap

Because we want to update the default variable, we need create custom _variable.scss. just copy from node_modules/bootstrap/scss/_variables.scss

//
// Color system
//

// stylelint-disable
$white: #fff !default;
$gray-100: #f8f9fa !default;
$gray-200: #e9ecef !default;

3. last include index.scss to .angular-cli.json:

"styles": [
"styles.css",
"assets/bootstrap/index.scss"
],

Now, every time when you want to overwrite default variable from bootstrap, just add to _variable.scss and variable default will change.

SASS: Overriding Variables in External Components

Declaring !default for a variable in SASS basically says "Hey this variable means this, unless otherwise specified somewhere else". This "somewhere else" can be above or below your variable, which makes it very handy for creating themes or working with frameworks where you'd like to preserve the vendor provided files incase of future updates.

So, you should be able to declare $btn-font-weight: normal; in main.scss and have it overwrite the downstream $btn-font-weight: bold !default; in _variables.scss.

That said, based on your answer that moving $btn-font-weight: normal; to the end of your main.scss compiles correctly, I'd suspect you've got another $btn-font-weight: not-!default in one of your other imported files or you're missing a semi-colon or some such syntax error.

You can to compile with sourcemaps enabled to debug this problem, as described in this link.



Related Topics



Leave a reply



Submit