理解Sass中变量作用域

发布于 大漠

在这篇文章中我们将一起深入探讨Sass的变量和变量作用域。变量作用域的描述是根据上下来定义和在哪使用变量。

首先,我们将介绍Sass作用域范围。然后,将解释两个用在变量值中标签,这两个标签非常有用。最后将简单介绍可用的函数,用来检查是否存在一个变量。

Sass变量作用域

Sass支持两种类型变量:局部变量全局变量

默认情况之下,所有定义在任何选择器之外的变量被认为是全局变量。这意味着他们可以在样式表中任意地方被访问。例如,这里有一个全局变量:

$bg-color: green;

另一方面,定义在选择器内的变量称之为局部变量。后面我们将研究如何自定义他们的行为。但是现在,让我们看看我们的第一个示例。

在这里,我们定义了一个混合宏,然后在里面设置了一个$btn-bg-color变量。这是一个局部变量,他只在mixin内部可见:

@mixin button-style {
    $btn-bg-color: lightblue;
    color: $btn-bg-color;
}

接下来,我们调用这个mixin:

button {
    @include button-style;
}

编译出来的CSS:

button {
    color: lightblue;
}

然而,想象一下,我们也使用这个变量(但不是mixin),而是在一个选择器中:

.wrap {
    background: $btn-bg-color;
}

此时,编译器(命令终端)会报这样的错误:

Undefined variable: "$btn-bg-color".

这是可以预料的是吧?我们试图在一个混合宏中调用一个局部变量。别担心,正如上面提到的,接下来的内容,我们会解决这个问题。

##嵌套选择器

值得一提的是,如果我们在一个选择器内声明了一个变量,嵌套在里面的其他选择器中都可以访问它。这里有一个例子:

.wrap {
    $bg-color: red;
     
    &:after {
        background: lighten($bg-color, 10%);
    }
}

编译出来的CSS:

.wrap:after {
    background: #ff3333;
}

然而,看看下面的例子,我们定义了一个函数,然后在嵌套的选择器中使用这个函数:

@function my-function() {
    $text-color: black;
    @return $text-color;
}
     
.wrap {
    color: my-function();
     
    &:after{
        background: $text-color;
    }
}

如果我们试图编译这个,我们会得到同样的错误。

Undefined variable: "$text-color".

再一次,这是因为我们无法访问$text-color变量。它不是直接定义在你选择器,而是在选择器内部调用了定义的函数。

变量名称

全局变量和局部变量可以定义相同的变量名。我们通过下面的示例来证明这一点:

$text-color: tomato;
 
@mixin button-style {
    $text-color: lime;
    color: $text-color;
}
     
@mixin link-style {
    $text-color: black;
    color: $text-color;
}

我们定义了三个相同变量名的变量,只是他们具有不同的值。第一个是全局变量,其他两个是局部变量。

在样式这样调用他们:

button {
    @include button-style;
}
      
a {
    @include link-style;
}
      
.wrap {
    background: $text-color;
}

编译出来的CSS:

button {
    color: lime;
}
     
a {
    color: black;
}
     
.wrap {
    background: tomato;
}

这是你所期望的结果?

请记住,除非我们使用Sass当前版本(3.4版本)编译,不然是看不到这些样式。比如说,假设我们使用的是Sass3.3版本,那么编译出来的CSS像这样:

button {
    color: lime;
}
     
a {
    color: black;
}
     
.wrap {
    background: black;
}

很明显,.wrap选择器的背景颜色不同。早些Sass版本(LibSass也一样)说,如果我们在本地重新定义了一个全局变量(如text-color),这将是新的全局变量。所以,在我们的示例中编译样式时取决于我们声明的变量的顺序和mixin的顺序。

default标志

这个标志让我们设置一个变量值,以防还没有设置或这个变量的值为null(视为未赋值)。更好的解释是我们在真实的场景中使用他,假设我们有一个这样的项目,其结构如下:

Project-Name/
    ├── ...
    ├── css/
    │   └── app.css
    └── scss/
        ├── _config.scss
        ├── _variables.scss
        ├── _mixins.scss
        └── app.scss

app.scss文件有这样一段代码:

@import "config";
@import "variables";
@import "mixins";
     
button {
    @include button-style;
}
 
// more styles

让我们来看看部分文件中的内容。

首先在variables,scss文件中包含了我们要用的变量:

$btn-bg-color: lightblue !default;
$btn-bg-color-hover: darken($btn-bg-color, 5%);
     
// more variables

注意在btn-bg-color变量的值后面添加了一个default标志。

其二,在mixins.scss文件中包含了我们要使用的混合宏:

@mixin button-style ($bg-color: $btn-bg-color, $bg-color-hover: $btn-bg-color-hover) {
    background-color: $bg-color;
    // more styles
         
    &:hover {
        background-color: $bg-color-hover;
        // more styles  
    }
}
     
// more mixins

然而,在编译出来的app.css文件中的代码将像下面:

button {
    color: lightblue;
}
     
button:hover {
    background-color: #99cfe0;
}

所以,我们的按钮采用的是默认样式。但是,假设我们想要通过自定义一个值来覆盖他们。要做到这一点,我们可以在config.scss文件中重新分配(默认)变量:

$btn-bg-color: chocolate;
     
// more variables

设置的变量值为chocolate将导致变量会忽略带有default标记的lightblue值。因此,生成的CSS将会变成下面这样:

button {
    color: chocolate;
}
     
button:hover {
    background-color: #bc5e1b;
}

**注:**我们在btn-bg-color变量后面没有添加default标记。编译出来的CSS将像这样:

button {
    color: lightblue;
}
     
// hover styles

global标志

第二个标志帮助我们改变一个局部变量的作用范围。

不知道你是否还记得我们第一个示例编译时出现的错误?那么好,因为我们试图在.wrap选择器中使用btn-bg-color变量。让我们来修改一下我们的示例,在变量的值中添加global新标志。下面是修改后样式:

@mixin button-style {
    $btn-bg-color: lightblue !global;
    color: $btn-bg-color;
}
     
button {
    @include button-style;
}
     
.wrap {
    background: $btn-bg-color;
}

正如下面所示代码,因为有了这个标志,编译时不会有报错代码:

button {
    color: lightblue;
}
     
.wrap {
    background: lightblue;
}

global标志是用的,但得记住,总是通过这个标志来修改一个变量的范围并不是一个很好的实践。

检查一个变量是否存在

Sass提供了两个函数,用来测试一个变量是否存在。我们可以使用variable-existsglobal-variable-exists函数来检查我们的局部变量或全局变量是否分别存在。

举例来说,这是一个常见的示例。我们定义了一个变量,变量值是引用Google Fonts的一个绝对路径。然后,我们在样式表中选择字体,但前担是相关的变量被实例化。

$google-font: "http://fonts.googleapis.com/css?family=Alegreya";
     
@if(global-variable-exists(google-font)) {
    @import url($google-font);
}

结果是:

@import url("http://fonts.googleapis.com/css?family=Alegreya");

结论

在这篇文章中,我们介绍了Sass变量作用域的概念。通过不同的示例,让我们更能清楚的了解变量作用域,所以希望你现在能更好的理解变量的作用域是如何工作的。你可以在SassMeister中找到本文用到的所有例子。如果你有任何问题或者想法,欢迎在下面的评论中给我们留言。

本文根据@George Martsoukos的《Understanding Variable Scope in Sass》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://webdesign.tutsplus.com/articles/understanding-variable-scope-in-sass--cms-23498