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
- variables’ dependencies in the framework are preserved and honors;
- 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
CSS Variables (Custom Properties) in Pseudo-Element "Content" Property
Can You Blur the Content Beneath/Behind a Div
Font-Feature-Settings: What Is the Correct Syntax
Ckeditor - Prevent Adding Image Dimensions as a CSS Style
Css3 Box Shadow on Top, Left, and Right Only
Css3 Appearance Property for Ie
Bootstrap 4 Ie 11 Does Not Work
Horizontal Centered Menu in CSS
How to Use Fontawesome in Chrome Extension
Firefox 30.0 - -Moz-Appearance: None Not Working
How to Check for Duplicate CSS Rules
How to Combine Cursor: Not-Allowed and Pointer-Events: None;
Bind Angularjs Variables into CSS Syntax
What Is the Function of "Overlay" Value of "Overflow" Property
Local Website Renders Differently Using (Ip Address or MAChine Name) VS Localhost