本文介绍了Bootstrap SASS 变量覆盖挑战的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题被标记为 这个,但请参阅此答案末尾附近的附录,了解该问题没有问什么,以及答案没有回答什么.

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.

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

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;

现在,假设上述变量在 _variables.scss 中定义.然后让我们在 _app-variables.scss 中说,我只覆盖了 $brand 变量以使其变为红色:$brand: red.由于SASS逐行解释代码,它首先将$brand设置为蓝色,然后将$text设置为蓝色(因为此时$brand为蓝色),最后将$brand设置为红色.所以最终结果是之后更改 $brand 不会影响任何基于 $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.

但显然这不是我想要的 - 我希望我对 $brand 的更改能够影响依赖它的一切.为了正确覆盖变量,我目前只是将 _variables.scss 的完整副本制作到 _app-variables.scss 中,然后从那时起在 _app-variables 中进行修改.同样,我将 _app-variables.scss 的完整副本复制到 _client-variables.scss 中,然后在 _client-variables.scss 中进行修改.显然,从维护的角度来看,这并不理想(轻描淡写) - 每次我对 _variables.scss(在 Bootstrap 升级的情况下)或 _app-variables.scss 进行修改时,我都必须手动将更改向下传递文件覆盖堆栈.此外,我不得不重新声明大量我什至可能无法覆盖的变量.

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.

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

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?

附录:
这是我已经考虑过的一种技术:以相反的顺序包含文件,对所有变量使用 !default(在 这个问题).所以这是如何进行的:

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)

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

推荐答案

已解决,但不知道从哪个版本开始.我相信解决方案本来可以一直可用.测试:

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

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

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

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

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;
}

挑战在于:

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

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

更准确地说:

在应用程序的 SCSS 中包含框架,这样 $brand-color 将始终是 $brand-warning 的反函数,无论它的值在框架.

解决方案

主文件如下所示:

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;
}

结果:

> sassc main.scss

a {
  color: blue; }

说明

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

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

在作用域内,我们@import 框架的变量.因为此时每个变量都没有值,每个变量都被创建并分配了它的 !default 值.

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.

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

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.

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

这意味着在这个文件中

%scope {
  @import "bootstrap/variables";

  $brand-primary: black !global;

  @debug $brand-primary;
}

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

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

将变量分成两部分:

%scope {
  @import "bootstrap/variables";

  $brand-primary: black !global;

  @debug $brand-primary;
}

@debug $brand-primary;

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

The second @debug will indeed correctly print black.

这篇关于Bootstrap SASS 变量覆盖挑战的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-24 04:22