【问题标题】:SASS Multiple levels of variable precedence/inheritanceSASS 多级变量优先级/继承
【发布时间】:2017-07-10 10:51:39
【问题描述】:

我正在使用 Laravel Mix 和 Webpack 进行 SASS 预处理。

我的网站中有两个“主题”,我想精简它们,在需要的地方继承变量。例如,我的主要主题将按以下顺序包括:

// Primary theme
@import "./primary-variables.scss";
@import "/path/to/default/theme/main.scss";

我的默认主题如下所示:

// Default theme
@import "./default-variables.scss";
@import "~bootstrap-sass/assets/stylesheets/_bootstrap";

与this question 类似,我首先包含主变量,然后是默认主题变量,最后是引导程序。

在我的默认主题中,我将!default 添加到所有变量中,以便在它们重新定义 Bootstrap 的地方优先使用它们,而在新的地方它们将成为默认值。主主题根本不使用!default。

工作示例

如果 Bootstrap 将 $brand-danger 定义为 red !default,我的默认主题将其重新定义为 blue !default,而我的主主题将其重新定义为 yellow,我的渲染输出将是黄色 - 太好了!

问题

当我需要引用仅在我的主要主题的其他级别定义的变量时。例如:

// Primary theme:
// This fails since I haven't defined $brand-primary in my primary theme
$my-primary-theme-variable: $brand-primary;

现在构建失败并显示错误消息primary-theme/src/scss/main.scss doesn't export content。

解决方法

我可以通过将整个 Bootstrap 变量文件复制到我的主主题并根据需要更改变量来解决此问题,但我真的不想这样做。

问题

SASS 变量处理器实际上是如何工作的?我是否可以只更改主题中的一个 Bootstrap 变量而不必重新定义整个文件?


This question 非常相似。

【问题讨论】:

    标签: css twitter-bootstrap sass laravel-mix


    【解决方案1】:

    您似乎正在使用 @include 导入您的 SCSS,请尝试使用 @import - 如果这只是问题中的错字,请告诉我:- )

    @import "./primary-variables.scss",
            "/path/to/default/theme/main.scss"
    ;
    

    我在您所指的the question 上添加了一些简短的注释。 关于 !default 标志需要了解的重要一点是,它在选择器中使用时生效,并且不会重新定义变量。

    Sass 在处理变量时不会向前看——它会打印出当前值。在此示例中,.class-1 将是 red,因为它在选择器中使用后重新定义,而 .class-2 将是蓝色,因为没有默认标志。

    $brand-color: red !default; // defined
    .class-1 { background-color: $brand-color; }  // red
    
    $brand-color: blue;         // re-defined
    .class-2 { background-color: $brand-color; }  // blue
    

    默认标志将导致 Sass 跳过变量重新定义。在此示例中,结果将是 red,因为它是首先定义的。由于默认标志,以下两个重新定义被忽略。

    $brand-color: red !default;   // defined
    $brand-color: blue !default;  // ignored 
    $brand-color: green !default; // ignored
    .class-1 { background-color: $brand-color; }  // red
    

    在这种情况下,来自配置的所有变量都将被使用 - 如果未在 config 中定义,则来自 partial-1 的变量和最后一个 partial-2 将定义其他两个中未定义的任何变量。

    @import '_config.scss';    // definition
    @import '_partial-1.scss'; // contains defaults
    @import '_partial-2.scss'; // contains defaults
    

    希望它有意义:-)


    导入结构

    //  _default-theme.scss
    @import '_default-variables.scss', '_bootstrap.scss';
    
    //  _primary-theme.scss
    //  primary variables will override defaults or use defaults if not defined
    @import '_primary-variables.scss', '_default-theme.scss';
    
    // style.scss
    @import '_primary-theme.scss'; // or '_default-theme.scss'
    

    范围

    如果您的默认主题和主主题具有每个主题独有的内容,您可以创建一个作用域混合来处理编译的内容。

    这是一个非常初级的版本:

    //  _scope.scss
    $scope-context: null !default;
    @function scope($scopes: null, $true: true, $false: false) { 
      @each $scope in $scope-context {  
        @if index($scopes, $scope) { @return $true }  
      }  
      @return $false;  
    } 
    @mixin scope($scopes: null) { 
      @if scope($scopes) or length($scopes) == 0 and not $scope-context { 
        @content; 
      } 
    }
    

    工作原理

    范围 mixin 接受一个上下文参数和一个内容块 @content。如果传递的上下文与全局变量 ($scope-context) 匹配,则呈现内容块。

    //  _default-theme.scss
    .class { content: 'Will show in both themes'; }
    
    @include scope(default-theme){
      .class { content: 'Will only show in the default theme'; }
    }
    
    @include scope(primary-theme){
      .class { content: 'Will only show in the primary theme'; }
    }
    
    //  can also be used as "if" function
    .class {
      content: scope(default-theme, 'Is default', 'Not default')
    }
    

    在您的情况下,在默认变量和主变量中定义 $scope-context

    // _default-variables.scss
    $scope-context: default-theme !default;
    
    // _primary-variables.scss
    $scope-context: primary-theme;
    

    ...并将 _scope.scss 添加到 _default-theme.scss

    //  _default-theme.scss
    @import '_default-variables.scss', '_bootstrap.scss', '_scope.scss';   
    

    【讨论】:

    • 对不起,是的,这只是一个错字:-)
    • 谢谢 - 这很有意义并且很容易理解。我的问题更多是关于使用当时未定义但稍后定义的变量。例如-在您的示例中,我可能只想在_partial-2.scss 中定义$brand-color,但我可能想在另一个定义中的_config.scss 中使用它,例如$my-var: $brand-color。此示例特定于引导程序,我可能希望在自定义定义中重新使用引导程序变量,而不必重新定义整个引导程序变量文件以使变量处于同一范围内。这可能吗?还是我一厢情愿?
    • 需要澄清两个问题:您的主题是编译成一个还是两个 CSS 文件?默认主题是否只使用默认变量?
    • 是的 - 一个已编译的 CSS 文件。它可以根据您使用的主题从任一主题编译(第二个主题继承第一个主题的部分,但第一个是独立的)。默认主题有一些调整变量,第二个主题也是如此。
    • 我已经更新了答案(在水平线下方)——希望我们越来越近 :-)
    【解决方案2】:

    我发现的问题是我对 SASS 工作原理的假设是错误的。

    当你定义一个变量声明时,它的值在你写它的时候被编译。例如,$my-var: $brand-primary 会在处理时将$brand-primary 的当前值分配给$my-var。

    这意味着我无法实现我想要的,即在 Bootstrap 的顶部包含一个最小变量文件,因为它只会更新变量本身,而不是在 Bootstrap 中引用该变量的任何其他变量.

    解决办法

    不是很优雅,而是为每个主题复制整个变量文件,并在每个地方根据需要进行调整。

    【讨论】:

    • 您还应该检查问题 31329177(包括我的评论)中排名最高的答案。那里的解决方案是更好的 IMO(但仍然不完美)。我认为这是 SASS 比较 LESS 中的一个缺陷,它会按照你的问题表现。尽管这在所有编程语言中都是“常见的”行为,但我知道在 CSS 上下文中这对我来说似乎是错误的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-11
    • 2019-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-16
    相关资源
    最近更新 更多