Sass两个先进特性与局限性

本文由大漠根据KrasimirTsonev的《Two handy and advanced SASS features and their limitations》所译,整个译文带有我们自己的理解与思想,如果译得不好或不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://krasimirtsonev.com/blog/article/Two-handy-and-advanced-SASS-features-and-their-limitations,以及作者相关信息

——作者:KrasimirTsonev

——译者:大漠

我真的很喜欢Sass,并且在我的日常工作中很多时候在使用Sass。他有很有很有用的功能。但是有很些东西我想做却不能做,他的语法和功能有所限制。今天我想分享一下我在使用Sass的一些发现,同时我也想知道你是否碰到这些限制以及你又是如何绕过他们。

插值Interpolation

使用CSS预处理器语言的一个主要原因是想使用Sass获得一个更好的结构体系。比如说你想写更干净的、高效的和面向对象的CSS。Sass中的插值(Interpolation)就是重要的一部分。让我们看一下下面的例子:

$properties: (margin, padding);
@mixin set-value($side, $value) {
    @each $prop in $properties {
        #{$prop}-#{$side}: $value;
    }
}
.login-box {
    @include set-value(top, 14px);
}

它可以让变量和属性工作的很完美,上面的代码编译成CSS:

.login-box {
    margin-top: 14px;
    padding-top: 14px;
}

这是Sass插值中一个简单的实例。当你想设置属性值的时候你可以使用字符串插入进来。另一个有用的用法是构建一个选择器。可以这样使用:

@mixin generate-sizes($class, $small, $medium, $big) {
    .#{$class}-small { font-size: $small; }
    .#{$class}-medium { font-size: $medium; }
    .#{$class}-big { font-size: $big; }
}
@include generate-sizes("header-text", 12px, 20px, 40px);

编译出来的CSS:

.header-text-small { font-size: 12px; }
.header-text-medium { font-size: 20px; }
.header-text-big { font-size: 40px; }

一旦你发现这一点,你就会想到超级酷的mixins,用来生成代码或者生成另一个mixins。然而,这并不完全是可能的。第一个限制,这可能会很删除用于Sass变量的插值。

$margin-big: 40px;
$margin-medium: 20px;
$margin-small: 12px;
@mixin set-value($size) {
    margin-top: $margin-#{$size};
}
.login-box {
    @include set-value(big);
}

上面的Sass代码编译出来,你会得到下面的信息:

error style.scss (Line 5: Undefined variable: "$margin-".)

所以,#{}语法并不是随处可用,你也不能在mixin中调用:

@mixin updated-status {
    margin-top: 20px;
    background: #F00;
}
$flag: "status";
.navigation {
    @include updated-#{$flag};
}

上面的代码在编译成CSS时同样会报错:

error style.scss (Line 7: Invalid CSS after "...nclude updated-": expected "}", was "#{$flag};")

幸运的是,可以使用@extend中使用插值。例如:

%updated-status {
    margin-top: 20px;
    background: #F00;
}
.selected-status {
    font-weight: bold;
}
$flag: "status";
.navigation {
    @extend %updated-#{$flag};
    @extend .selected-#{$flag};
}

上面的Sass代码是可以运行的,因为他给了我们力量,可以动态的插入.class%placeholder。当然他们不能接受像mixin这样的参数,上面的代码编译出来的CSS:

.navigation {
    margin-top: 20px;
    background: #F00;
}
.selected-status, .navigation {
    font-weight: bold;
}

在Sass的社区正在积极讨论插值的局限性,谁又知道呢,也许我们很快将能够使用这些技术也说不定呢。

使用列表作为一个源生成器

如果你在函数或mixin中需要未知数量的参数,这个列表就显得非常的有用。前几天,我遇到了一个问题,我没能解决,至使我不得不改变我的Sass架构。假设我们有下面一段代码:

%margin-reset { margin: 0; }
%padding-reset { padding: 0; }
%size-reset { width: 100%; height: 100%; }
@mixin add-styles($items) {
    @each $item in $items {
        @extend %#{$item};
    }
}
.footer, .header, .login-box {
    @include add-styles((
        margin-reset,
        padding-reset,
        size-reset
    ));
}

编译出来的CSS:

.footer, .header, .login-box {
    margin: 0;
}
.footer, .header, .login-box {
    padding: 0;
}
.footer, .header, .login-box {
    width: 100%;
    height: 100%;
}

到目前为止还好。现在我能够使用@extend扩展我想要的很多%placeholders。但mixins呢?我在想可以用mixin代替%placeholders嵌套吗?第一个问题是,mixins接受参数(如果你有一个不行,就必须考虑重构)。正如你已经看到,主要的想法是通过一个列表,通过后面的元素来读取。每个元素可以是一个mixin或者%placeholders。我发现只有一种方式来区分它们。如果我需要扩展一个占位符,我需要传它的名字,否则我通过另一个列表包含mixin的名称及其参数。例如:

@mixin border-solid($width, $color) {
    border: solid #{$width} #{$color};
}
...
.footer, .header, .login-box {
    @include add-styles((
        margin-reset,
        padding-reset,
        size-reset,
        (border-solid, 3px, #F90)
    ));
}

所以,当我遍历列表中的所有列表项时我必须先检查当前的一个列表。幸运的是有一个函数称为type_of和它返回传递的变量的类型。

@mixin add-styles($items) {
    @each $item in $items {
        @if type_of($item) == "list" {
            // call a mixin
        } @else {
            @extend %#{$item};
        }
    }
}

就像我说的,在本文的第一部分,我们在mixin中不能用插值。像这样的代码实际上是错误的:

@include #{$item}();

据我所了解,目前没有解决方案,和我使用的一个@if...@else

@mixin add-styles($items) {
    @each $item in $items {
        @if type_of($item) == "list" {
            @if nth($item, 1) == "border-solid" {
                @include border-solid(nth($item, 2), nth($item, 3));
            }
        } @else {
            @extend %#{$item};
        }
    }
}

当然我也不喜欢这样的代码。主要是因为我想用它来描述每一个mixin在添加样式。不管怎么样,我是准备使用它,即使这个版本没有工作。一旦我删除%placeholders和只调用(border-solid,3px,#f90),会得到:

Syntax error: Invalid CSS after "%": expected placeholder name, was "3px"

如果你有一个元素的列表它被转换为字符串和我用来检查@if type_of($item) == "list"不能正常工作,将会得到一个@else参数和试图@extend一个%placeholder

总结

虽然Sass有一定的局限性,但Sass仍然是一个美妙的预处理器语言,他带来很多有用的特性。

译者手语:整个翻译依照原文线路进行,并在翻译过程略加了个人对技术的理解。如果翻译有不对之处,还烦请同行朋友指点。谢谢!

出处:

英文原文:http://krasimirtsonev.com/blog/article/Two-handy-and-advanced-SASS-features-and-their-limitations

中文译文:http://www.w3cplus.com/preprocessor/two-handy-and-advanced-sass-features-and-their-limitations.html