Bootstrap SASS变量覆盖挑战

jby*_*yrd 14 css variables overriding sass twitter-bootstrap-3

编辑:这个问题被标记为重复这一个,但看到接近这个答案的末尾增编,看看这个问题不问,什么回答不回答.

我正在使用一个使用Bootstrap 3的Web应用程序.我有一个基本的3层覆盖架构,其中1)Bootstrap的_variables.scss包含核心变量,2)_app-variables.scss包含覆盖Bootstrap的基本app变量_variables.scss和3)_client-variables.scss包含覆盖_app-variables.scss的特定于客户端的自定义.#2或#3(或两者)都可以是空白文件.所以这是覆盖顺序:

_variables.scss // Bootstrap's core
_app-variables.scss // App base
_client-variables.scss // Client-specific
Run Code Online (Sandbox Code Playgroud)

在理论上足够简单,但由于我称之为"变量依赖"而出现问题 - 变量被定义为其他变量.例如:

$brand: blue;
$text: $brand;
Run Code Online (Sandbox Code Playgroud)

现在,假设上述变量在_variables.scss中定义.然后让我们说在_app-variables.scss中,我只覆盖$ brand变量使其变为红色:$brand: red.由于SASS按顺序逐行解释代码,它首先将$ brand设置为蓝色,然后将$ text设置为蓝色(因为$ brand在此时为蓝色),最后将$ 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.
Run Code Online (Sandbox Code Playgroud)

但显然这不是我想要的 - 我希望我的$品牌改变能够影响所有依赖它的东西.为了正确覆盖变量,我现在只是将_variables.scss的完整副本复制到_app-variables.scss中,然后在_app-variables中进行修改.同样地,我将_app-variables.scss的完整副本复制到_client-variables.scss中,然后在_client-variables.scss中进行修改.从维护的角度来看,这显然不太理想(轻描淡写) - 每当我对_variables.scss(在Bootstrap升级的情况下)或_app-variables.scss进行修改时,我都必须手动涓流改变文件覆盖堆栈.此外,我不得不重新宣布一些我甚至可能无法克服的变量.

我发现LESS有他们所谓的"延迟加载"(http://lesscss.org/features/#variables-feature-lazy-loading),其中变量的最后一个定义在任何地方使用,甚至在最后一个定义之前.我相信这会解决我的问题.但有没有人知道使用SASS的适当的变量覆盖解决方案?

附录:
这是我已经考虑过的一种技术:以相反的顺序包含文件,!default用于所有变量(这个技术也在这个问题的答案中提出).所以这是如何发挥作用:

_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)
Run Code Online (Sandbox Code Playgroud)

所以解决方案几乎是完美的.但是,现在在我的覆盖文件中,我无法访问Bootstrap的_variables.scss中定义的变量,如果我想使用其他Bootstrap变量来定义我的变量覆盖(或我自己的其他自定义变量),我将需要这些变量.例如,我可能想要这样做:$custom-var: $grid-gutter-width / 2;

Pie*_*mon 17

解决了,但我不知道这个版本的工作原理.我相信解决方案始终可用.测试:

> sassc --version

sassc: 3.2.1
libsass: 3.2.5
sass2scss: 1.0.3
Run Code Online (Sandbox Code Playgroud)

我们将使用简化的环境,因此文件名与Bootstrap不匹配.


挑战

给定一个我们无法控制的框架(例如,仅在Continuous Integration环境中安装,在我们的机器中不可用),它以下列方式表示SCSS变量:

// bootstrap/_variables.scss

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

$link-color: $brand-primary !default;
Run Code Online (Sandbox Code Playgroud)

并在同一框架中给出一个使用变量的文件:

// bootstrap/main.scss

a:link, a:visited {
  color: $link-color;
}
Run Code Online (Sandbox Code Playgroud)

挑战是:

以这样的方式将框架包含在您自己的应用程序的SCSS中

  1. 变量在框架中的依赖关系得到保留和尊重;
  2. 您可以依赖于默认值,但仍然可以更改框架依赖项的结果.

更确切地说:

将框架包含在应用程序的SCSS中,使其$brand-color始终$brand-warning与其框架中的值无关.

主文件看起来像这样:

// application.scss

@import "variables";
@import "bootstrap/variables";
@import "bootstrap/main";
Run Code Online (Sandbox Code Playgroud)

你的变量文件看起来像这样:

// _variables.scss

%scope {
  @import "bootstrap/variables";

  $brand-primary: invert($brand-warning) !global;
}
Run Code Online (Sandbox Code Playgroud)

结果:

> sassc main.scss

a {
  color: blue; }
Run Code Online (Sandbox Code Playgroud)

说明

%scope部分不是SCSS的神奇之处,它只是一个带有名称的隐藏类scope,专门用于以后的扩展@extend.我们正在使用它来创建一个变量范围(因此名称).

在范围内我们@import是框架的变量.因为此时每个变量都没有值,每个变量都会被创建并赋值!default.

但这是噱头.变量不是全局变量,而是本地变量.我们可以访问它们,但它们不会污染全局范围,后者将用于在框架内派生变量.

事实上,当我们想要定义变量时,我们希望它们是全局变量,实际上我们使用!global关键字来表示SCSS将它们存储在全局范围内.


注意事项

有一个主要的警告:在定义变量时不能使用自己的变量.

这意味着在这个文件中

%scope {
  @import "bootstrap/variables";

  $brand-primary: black !global;

  @debug $brand-primary;
}
Run Code Online (Sandbox Code Playgroud)

@debug语句将打印在boostrap/_variables.scss中定义的默认值,而不是.black

拆分变量分为两部分:

%scope {
  @import "bootstrap/variables";

  $brand-primary: black !global;

  @debug $brand-primary;
}

@debug $brand-primary;
Run Code Online (Sandbox Code Playgroud)

第二个@debug确实会正确打印black.

  • 你可以通过这样定义它们来避免不能使用你自己的变量(这是非常重要的IMO)的警告:%scope {// import"boostrap/variables"; $ brand-primary:black; $ brand-primary:$ brand-primary!global; // debug $ brand-primary; 如果你追加"!global",sass似乎直接定义了全局范围内的变量.剩下的唯一问题是这个解决方案只能在一个层面上工作,而不能在以下结构上工作:bootstrap-styles> company-styles> project-styles (2认同)