【问题标题】:Bootstrap SASS variable override challengeBootstrap SASS 变量覆盖挑战
【发布时间】:2015-09-28 12:26:51
【问题描述】:

编辑:此问题被标记为与this one 重复,但请参阅此答案末尾附近的附录,以了解该问题没有问什么,以及答案没有'不回答。

我正在开发一个使用 Bootstrap 3 的网络应用程序。我有一个基本的 3 层覆盖架构,其中 1) Bootstrap 的 _variables.scss 包含核心变量,2) _app-variables.scss 包含基本应用程序变量覆盖 Bootstrap 的 _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

理论上很简单,但是由于我称之为“变量依赖项”的问题出现了——其中变量被定义为其他变量。例如:

$brand: blue;
$text: $brand;

现在,假设上述变量在_variables.scss 中定义。然后假设在 _app-variables.scss 中,我仅覆盖 $brand 变量以使其变为红色:$brand: red。由于 SASS 是按顺序逐行解释代码的,它首先将 $brand 设置为蓝色,然后将 $text 设置为蓝色(因为此时 $brand 为蓝色),最后将 $brand 设置为红色。所以最终结果是之后更改 $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.

但显然这不是我想要的——我希望我对 $brand 的更改能够影响依赖它的一切。为了正确覆盖变量,我目前只是将 _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 的合适的变量覆盖解决方案吗?

附录:
这是我已经考虑过的一种技术:以相反的顺序包含文件,对所有变量使用!defaultthis question 的答案中也建议使用此技术)。所以这就是结果:

_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)

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

【问题讨论】:

  • 我不知道你现在希望得到什么样的答案,因为这是“不是重复的”。如果不使用多个包含,您的要求是不可能的。
  • 多重包含(导入)到底是什么意思?在我的附录中描述的方法中,我使用了多个导入:@import "_variables";(Boostrap's),然后是@import "_app-variables.scss",然后是@import "_client-variables"。提前致谢。
  • 我认为我不需要把它拼出来。如果你想引用一个变量,它必须首先存在(这就是你得到的“未定义变量”错误的意思)。如果要覆盖默认变量并将其传播到所有其他默认变量,则必须提前声明。
  • 我知道,我明白这一点。您说“如果不使用多个包含,您所要求的是不可能的”,这意味着可以使用多个包含 - 我要问的是如何使用多个包含?或者不是吗?这可能只是 SASS 的“限制”; LESS 允许的东西。
  • 我遇到了您在附录中概述的确切问题,即无法访问我的覆盖中的默认变量。你找到解决办法了吗?

标签: css variables twitter-bootstrap-3 sass overriding


【解决方案1】:

已解决,但我不知道这适用于哪个版本。我相信解决方案可能一直可用。测试日期:

> sassc --version

sassc: 3.2.1
libsass: 3.2.5
sass2scss: 1.0.3

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


挑战

给定一个我们无法控制的框架(例如,仅安装在持续集成环境中并且在我们的机器中不可用),它以以下方式表达 SCSS 变量:

// bootstrap/_variables.scss

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

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

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

// bootstrap/main.scss

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

挑战是:

在您自己的应用程序的 SCSS 中包含该框架,以便

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

更准确地说:

在您的应用程序的 SCSS 中包含该框架,使 $brand-color 始终是 $brand-warning 的倒数,无论其在框架中的值是什么。

解决方案

主文件如下所示:

// application.scss

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

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

// _variables.scss

%scope {
  @import "bootstrap/variables";

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

结果:

> sassc main.scss

a {
  color: blue; }

说明

%scope 部分并不是 SCSS 的魔法,它只是一个名为 scope 的隐藏类,专用于以后的扩展 @extend。我们使用它只是为了创建一个变量范围(因此得名)。

在我们@import 框架变量的范围内。因为此时每个变量都没有值,每个变量都被创建并分配了其!default 值。

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

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


注意事项

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

也就是说在这个文件中

%scope {
  @import "bootstrap/variables";

  $brand-primary: black !global;

  @debug $brand-primary;
}

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

解决方案

将变量分成两部分:

%scope {
  @import "bootstrap/variables";

  $brand-primary: black !global;

  @debug $brand-primary;
}

@debug $brand-primary;

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

【讨论】:

  • @jbyrd 你会接受这个作为一个获胜的提议:)
  • 您可以通过像这样定义它们来避免无法使用自己的变量(这是非常重要的 IMO)的警告: %scope { //import "boostrap/variables"; $brand-primary: 黑色; $brand-primary: $brand-primary !global; //调试 $brand-primary;如果您附加“!global”,sass 似乎确实直接在全局范围内定义变量。剩下的唯一问题是该解决方案仅在一个级别上有效,而不是在以下结构上有效:bootstrap-styles > company-styles > project-styles
  • 再次 Ping @jbyrd :)
  • 刚刚看到这个 - 我有一段时间没有使用 Sass,但我确实记得这个挑战 - 这是一个非常聪明的解决方案!我实际上并没有尝试过实现它,但它似乎是有道理的,所以我会接受这个作为答案。
  • @Pier 是的,当我尝试该技术时,我正在分享我的经验 - 警告不仅适用于您自己对覆盖变量的使用,还适用于引导文件中变量的任何使用 - 当这些文件被导入所有引用都使用默认值解析。一个新的作用域块解决了这个问题,但是您需要注意在原始作用域块中引用了哪些引导变量。也就是说,如果您希望避免复制和粘贴,您的回答仍然是我见过的针对此问题的最佳解决方法。
【解决方案2】:

使用 Bootstrap 4 或 bootstrap-sass 在 _variables.scss 中使用 !default 标志设置的所有变量。

因此,如果你在 bootstrap 的 _variables.scss 被包含之前设置了一个变量,当它被包含时,来自 _variables.scss 的值将被忽略。

所以我的 sass 入口文件可能看起来像这样......

@import "bootstrap-overrides";
@import "bootstrap/scss/bootstrap-flex";
@import "mixins/module";

【讨论】:

    【解决方案3】:

    在 Bootstrap 4 的 alpha 6 中,_variables.scss 中的所有变量都可以在 _custom.scss 中被覆盖,就像 mryarbles 所描述的那样。 但是,覆盖不会级联到其他元素,因为包含顺序是:

    @import "variables";
    @import "mixins";
    @import "custom";
    

    当我把它改成

    @import "custom";
    @import "variables";
    @import "mixins";
    

    它按预期工作。

    【讨论】:

      【解决方案4】:

      BS4 dev 分支中的 _custom.scss 文件已被删除。尝试使用以下顺序重新排序您的导入:

      设置

      @import "client-variables";
      @import "app-variables";
      @import "boostrap";
      @import "app-mixins";
      @import "client-mixins";
      

      确保将boostrap变量文件_variables.scss的内容复制到app-variablesclient-variables。将 !default 保留在每个变量旁边以允许进一步覆盖。

      说明

      所有引导变量都用!default 声明。来自萨斯reference

      如果变量尚未分配,您可以通过将 !default 标志添加到值的末尾来分配变量。这意味着如果变量已经被赋值,它不会被重新赋值,但如果它还没有值,它将被赋予一个。

      • Bootstrap 将尊重已在顶部定义的所有变量,使 app_variables 具有更高的优先级,client_variables 具有最高优先级。
      • 您需要将引导程序_variables 中的所有变量声明复制到app-variablesclient-variables,这样您就可以根据需要拥有一个自定义变量。 (缺点是每次引导更新都难以维护)
      • 所有变量现在都可以在您的app-mixinsclient-mixins 中使用

      【讨论】:

        猜你喜欢
        • 2020-06-14
        • 2016-04-18
        • 1970-01-01
        • 2013-06-06
        • 2013-12-24
        • 1970-01-01
        • 2018-01-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多