EDIT: This question was marked as a duplicate of this one, but see the addendum near the end of this answer to see what that question doesn't ask, and what the answer doesn't answer.
I'm working on a web app that uses Bootstrap 3. I have a basic 3-layer override architecture, where 1) Bootstrap's _variables.scss contains the core variables, 2) _app-variables.scss contains the base app variables that override Bootstrap's _variables.scss, and 3) _client-variables.scss contains client-specific customizations that override _app-variables.scss. Either #2 or #3 (or both) can be blank files. So here's the override order:
_variables.scss // Bootstrap's core
_app-variables.scss // App base
_client-variables.scss // Client-specific
Simple enough in theory, but a problem arises because of what I'll call "variable dependencies" -- where variables are defined as other variables. For example:
$brand: blue;
$text: $brand;
Now, let's say the above variables are defined in _variables.scss. Then let's say in _app-variables.scss, I override only the $brand variable to make it red: $brand: red
. Since SASS interprets the code line by line sequentially, it will first set $brand to blue, then it will set $text to blue (because $brand is blue at that point), and finally it will set $brand to red. So the end result is that changing $brand afterwards does not affect any variables that were based on the old value of $brand:
_variables.scss
---------------------
$brand: blue;
$text: $brand; // $text = blue
.
.
.
_app-variables.scss
---------------------
$brand: red; // this does not affect $text, b/c $text was already set to blue above.
But obviously that's not what I want - I want my change of $brand to affect everything that depends on it. In order to properly override variables, I'm currently just making a full copy of _variables.scss into _app-variables.scss, and then making modifications within _app-variables from that point. And similarly I'm making a full copy of _app-variables.scss into _client-variables.scss and then making modifications within _client-variables.scss at that point. Obviously this is less than ideal (understatement) from a maintenance point of view - everytime I make a modification to _variables.scss (in the case of a Bootstrap upgrade) or _app-variables.scss, I have to manual trickle the changes down the file override stack. And plus I'm having to redeclare a ton of variables that I may not even be overriding.
I found out that LESS has what they call "lazy loading" (http://lesscss.org/features/#variables-feature-lazy-loading), where the last definition of a variable is used everywhere, even before the last definition. I believe this would solve my problem. But does anyone know a proper variable-override solution using SASS?
ADDENDUM:
Here's one technique I've already thought through: include the files in reverse order, using !default
for all variables (this technique was also suggested in the answer to this question). So here's how this would play out:
_app-variables.scss
---------------------
$brand: red !default; // $brand is set to red here, overriding _variables.scss's blue.
.
.
.
_variables.scss
---------------------
$brand: blue !default; // brand already set in _app-variables.scss, so not overridden here.
$text: $brand !default; // $text = red (desired behavior)
So that solution is almost perfect. However, now in my override files, I don't have access to variables defined in Bootstrap's _variables.scss, which I would need if I wanted to define my variable overrides (or my own additional custom variables) using other Bootstrap variables. For example, I might want to do: $custom-var: $grid-gutter-width / 2;
@import "_variables";
(Boostrap's), then@import "_app-variables.scss"
, then@import "_client-variables"
. Thanks in advance.