Sass的新特性

发布于 大漠

Sass的新特性

本文由大漠根据的《Looking Into the Future of Sass》所译,整个译文带有我们自己的理解与思想,如果译得不好或不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://davidwalsh.name/future-sass,以及作者相关信息

——作者:

——译者:大漠

Sass是CSS的预处理器,这也是现在最常见讨论的一个话题。Sass最早是2007年由Hampton Catlin提出。Sass到现在已经走了很长的路了,到现在也是最常见的CSS预处理程序。

如果您还不知道什么是Sass,我强烈推荐您阅读一下David Walsh写的这文章和Chris Coyier写的文章

如果您不喜欢阅读英文文章,可以阅读W3cplus中有关于Sass的系列教程

不管什么情况之下,我将假定您基本都了解Sass,你们当中有一些人甚至是Sass的铁杆粉丝!这些都不先考虑,如果有一篇博客介绍Sass的未来特性,那多好。

Sass3.3即将到来

这一段时间Nathan Weizenbaum和Chris Eppstein正致力于Sass3.3版本开发。截止今天,Sass3.3的alpha版本已经可以使用了(当然其中还有不足),但我相信官方版本将会很快公布(虽然没有具体发布日期)。

那什么是全新的Sass版本呢?里面有很多新东西,他们中的大多数并没有正式宣布做Sass3.3版本,所以我只有猜想:

从一个方面说明,如果你有机会参加2013年CSS峰会,你不要错过它。特别是Chris Eppstein将在峰会上谈论很多很棒的Sass3.3。

Sourcemaps

我认为Sass3.3版本最大的功能是具有Sourcemaps。其实Sourcemaps并不特定于Sass所有。它是一种与语言无关的方式映射到原始的生产代码之中,甚至是编译和压缩。这里有一篇相关的介绍

在开发者工具中查看一个元素,如果你想编辑样式,比如说是style.css:1(你的样式文件中的第一行)。你是没有办法可以编辑CSS样式文件,但Sass文件可以。

这基本上是的Sass sourcemaps派上用场。而style.css:1刚好是component.scss:42编译出来的,这样不是更好吗?

你使用sourcemaps Sass工作流,可以分五个步骤:

  • 你需要使用Chrome28+
  • 确认你使用的是Sass3.3 Alpha(gem install sass --pre)
  • chrome://flags中开启Developer Tools Experiments
  • 打开开发者工具,并到General tab中选择Enable source maps
  • 打开开发者工具,并到Experiments tab中选择Support for Sass
  • 使用sass --watch --sourcemap编译你的样式文件

到此,你的浏览器就可以使用DevTools Sass roucemaps(.map文件)将你的产品代码映射到你的开发者代码中。你现在可以点击(文件名和样式)和访问你的Sass文件。

注:截至今天,如果你在使用Compass0.13版本,Sass3.3 Alpha还存在一些严重的问题。你不能使用compass watch,现在你要使用sass --compass --sourcemap --watch style.scss:style.css.更多信息可以点击这里查看

有关于Sass sourcemap功能和开发者工具调试相关介绍,可以阅读《SASS调试》一文。

改善选择器&

你可能已经知道了参考选择器(&)。这是一个引用当前选择器用于嵌套规则,不能用于根级别嵌套(Sass抛出一个错误)。最简单的使用情况如下:

a {
    color: tomato;

    &:hover {
        color: deepskyblue;
    }
}

编译出来的CSS

a {
  color: tomato; 
}
a:hover {
  color: deepskyblue; 
}

这是最基本的。他们在这个参考选择器上取得了大量的改进,让我们看看其中的一对。

在选择器中使用&

修复了几个Bug,使用参考选择器在更复杂的选择器上,请参考下面的例子:

$base: ".module";
#{$base} {
    &#{$base}-something {
        /* ... */
    }
}

在本例中,您为您的模块定义某种基本选择器,然后想应用样式到某个元素和派生选择器(.module.module-something)。但按上面的代码写,编译代码时会报错:

error style.scss (Line 4: Invalid CSS after "    &#{$base}": expected "{", was "-something {""-something" may only be used at the beginning of a compound selector.)

在Sass下一个版本,我们将能够通过插值和参考选择器混合使用,参考资料

$base: ".module";
#{$base} {
    #{&}#{$base}-something {
        /* ... */
    }
}

当前,唯一的解决方法是从基本变量中删除.,并且显式的在选择器中使用:

$base: "module";
.#{$base} {
    &.#{$base}-something {
        /* ... */
    }
}

转译出来的CSS:

.module.module-something {
  /* ... */ 
}

这并不是怎么强大,因为在编码和在前嵌套选择器,迫使在编码中使用类名.。还是在等待新的&功能,对吗?

BEM-like语法

有一件事情我真的很期待,扩展选择器&能够运用在BEM语法上。如果你不是很熟悉BEM语法,我强烈建议你读一下这个帖子

如果你想了解更多有关于BEM相关的知识,可以点击w3cplus发表的有关于BEM教程

问题是在使用Sass的嵌套。让我们来看一个简单的例子:

.block {
    /* Base stuff */
}

.block__child {
    /* Sub-element of block */
}

.block--modifier {
    /* Variation of block */
}

这是你想要的。对吗?不幸的是,你不能在嵌套中使用(没有任何嵌套)。如果我们能像下面这样使用:

.block {
    /* Base stuff */
    &__child {
        /* Sub-element of block */
    }
    &--modifier {
        /* Variation of block */
    }
}

这将是可怕的。最好的语法,但截至今天,编译上面的代码仍然会报错:

error style.scss (Line 4: Invalid CSS after "    &": expected "{", was "__child {"
"__child" may only be used at the beginning of a compound selector.)

舍得庆幸的是,他们将提高参考选择器在这种语法上的某种程序上的使用(详细参考这里)。快速笔记,我们将不得不使用插入选择器:#{&}__child。这也没什么大不了的。

绑定父元素

这个例子是Ericam从Susy框架中提出的(参考这里)。他创建了一个mixin,使用参考选择器来制作了适合IE浏览器的@media规则:

@mixin respond-to($media, $ie-class:'ie') {
    @media (#{$media}) { @content; }
    // We need the parent selector here in order to mimic the @media bubbling.
    .#{$ie-class} & { @content; }
}

想法很简单:他被称为mixin,给@media传递一个有效的值,在大括号中写上所有想要的样式。这些样式将显示在一个@media块中。此外,通过参考选择器为IE创建另一个样式块。

// This works already.
.container { 
    @include respond-to('min-width: 30em') {
        color: red; 
    }
}

// This doesn't work.
@include respond-to('min-width: 30em') {
    .container { color: red; }
}

从内部调用mixin选择器工作是很强大的。然而从根标签调用mixin,Sass会报错(基本规则是不能包含父选择器引用字符&)。这是因为&选择器不能用于根一极。

可以理解的。然而它应该可用。这将防止Sass在这种情况之下报错,比如这个例子。希望在新的版本之中能解决这个问题,详细讨论可以参考这里

改善if()函数

你听过if()函数吗?这是一个众所周知的三元判断variable = condition ? true : false(javasctipr,PHP)。他像下面这样工作:

$a: 10;
$b: if($a > 5, blue, red); // blue

除了一个小问题,这个函数没有条件价值。把它简单,功能的工作原理是这样的:

  • 检查条件
  • 评估真的结果
  • 评估错的结果
  • 分配显示结果

当它应该是这样的工作的:

  • 检查条件
  • 评估显示结果
  • 分配显示结果

这看起来好像我很挑剔,但在这种情况下,一个结果不应该被显示。如下面的例子:

@function dosomething($argument) {
    $second-item: if(
       type-of($argument) == list, 
       nth($argument, 2), 
       $argument
    );
    @return $second-item;
}

// This works like a charm
dosomething( (item-1, item-2) );

// This throws an error
dosomething( only-item );

如果给定的参数是一个列表,那么函数返回列表中的第二个列表项;如果给定的参数不是一个列表,那么函数返回他的参数。不幸的是,这个函数,如果传的参数只是一个就会报错。

这个不应该失败。正常的行为会检查条件,在目前的情况下意识到这是错误的,所以会跳到第三点,甚至没有试图解析第二点。不幸的是if()解析了一切。

所以他们决定在内置解析器解决if()问题,详细请参考这里

行进的操作列表

Sass提供了相当多的函数来操作列表。他们功能都是非常强大的,尤其是join()函数,可以将一个列表附加到另一个列表中。他们正在考虑通过+操作符来操作列表,详细请阅读这里

$a: item-1, item-2, item-3;
$b: item-4, item-5, item-6;
/* Same as 
 * $c: join($a, $b);
 */
$c: $a + $b; // item-1, item-2, item-3, item-4, item-5, item-6

直到目前这只是一种想像,但尽管如此,我认为这是不错的。现在Crhis甚至还提出使用减号-来操作列表:

$a: item-1, item-2, item-3;
$b: item-3, item-4, item-1;
$c: $a - $b; // item-1, item-2, item-3, item-4

减号-操作符应该删除掉第一列中具有的第二列的列表项。这可能是一个强大的功能,当你想要删除你想要删除的。包括falsenull值:

$a: item-1, false, item-2, null, item-3;
/* Same as 
 * $a: reject($a, false); 
 * $a: reject($a, null);
 */
$a: $a - (false, null); // item-1, item-2, item-3

即使这是可能的,但Nathan似乎对此不太感兴趣——需要以唯一的语言来实施,就像Ruby一样,但并不是每个人都是熟悉Ruby。

列表就要介绍完了,我听到一个nth()函数,可以用来获取列表的第n个列表项,他可以接受负值,从列表的末尾开始索引列表项,而不是初始值(请参考这里)。为了得到列表中的最后一个列表项,你可以这样操作:

$list: a b c d e;
$last-item: nth($list, length($list)); // Old way
$last-item: nth($list, -1); // New way

一个新函数list-separator()

这是一个很小的飞跃,但我人为做Sass列表成员之一是非常不错的。

他们计算增加一个list-separator()函数用来决定一个列表中列表项的分隔符号是空格还是逗号(详情请点这里)。使用相当简单:

$a: item-1, item-2, item-3;
$b: item-1 item-2 item-3;
list-separator($a) -> comma
list-separator($b) -> space

函数返回逗号或空格。因为每管委会值在Sass中都被视为一个列表,通过一个单元素值将返回空格。

支持Maps

我花了一些时间来了解这个,他们似乎想让Sass3.3支持map功能(详细请点这里)。maps就像一个关联数组。一个A元素在B元素中的列表:

map = {
  A: B,
  C: D
}

这就是一个map,类似于JSON语言。到今天为止,我还不确定在一两层列表中Map有什么好处。这里有一个模拟Sass列表嵌套的例子:

$map: (
        A B,
        C D
      );

@each $pair in $map {
    $first-item  : nth($pair, 1);
    $second-item : nth($pair, 2);
}

它是非常棒的,也非常有意义。这也是我为什么不理解Sass要增加map语法。其实我们可以看到一个更好的原因:使语法结构更简单化。

在任何情况下,这是我能找到关于传入的语法:

$map: (
        a: b,
        c: d
      );

@for $key, $value in $map {
    /**
     * $key is what we called $first-item
     * $value is what we called $second-item
     */
}

到现在为止,我所了解的map就这些,其他的随后会有。有关于Sass的map功能信息可以点击这里

改善@for循环

我们喜欢循环,他功能是强大的。对于某些任务,他可以减少很多所需的代码。Sass提供了三种不同类型的循环:

  • @for让一个变量imn循环
  • @while当条件a为真时循环
  • @each从矩阵中遍历每个元素

这些功能都是非常强大的。然而@for循环有一个问题。你试过一个做递减的@for循环吗?如下面的例子:

@for $i from 5 through 1 {
    /* Do something with $i */
}

别麻烦了,这将会输出什么。甚至不是一个Sass差错。目前,只有按下面的方法来解决这个东西:

@for $i from -5 through -1 {
    /* Do something with abs($i) */
}

基本上,你把两个负值,使循环做递增,再者你可以使用abs($i)来代替$i,访问你想要的第一个值。

不管怎么说,他们打算在Sass3.3中修复这个bug(详细信息请点击这里)。Chris Eppstein还打算在循环中添加从1到另一个值做递增和递减。大致是这样的:

@for $i from 1 through 10 by 2 {
    /* Do something with $i */
}

然而Nathan Weizenbaum似乎没有合理的@for循环语法来处理这个边缘性的事情,他可以很容易的复制出:

@for $i from 1 through 10 {
    @if $i % 2 != 0 {
        /* Do something with $i */
    }
}

@at-root规则

好吧,我跟您说实话:这个对于我来说仍是一个谜。这个@at-root命令需要嵌套块并将其移到根一级。这功能是不错的,但是为什么呢?为什么你不能只是把它写在根一级呢?

我不能找到更多有关于@at-root规则(除了语法)更多的信息,这里有几个简单的使用例子:

/* Example 1 - Sass */  
.foo { 
    @at-root .bar { 
        color: gray; 
    } 
}

/* Example 1 - CSS */
.bar { color: gray; }

/* Example 2 - Sass */
.foo {
    @at-root .bar &;; {
        color: gray;
    }
} 

/* Example 2 - CSS */
.bar .foo { color: gray; }

/* Example 3 - Sass */
.foo {
    @at-root {
        .bar {
            color: gray;
        }
    }
}

/* Example 3 - CSS */
.bar { color: gray; }

你知道吗?我不会在这个@at-root上花太多时间,对于他们将怎么实现这个特性,他们看起来很有自信,但是我没有看到太多用例。在这个问题上,这里有更多的讨论信息。

新的字符串操作函数

当我从Sass的代码分支中看到这些,我意识到他们打算增加一些字符串操作函数来缓解quote(string)unquote(string)函数功能。参考文档请点击这里。从里面我发现五个新的字符串操作函数:

  • str_length(string):返回$string长度
  • str_insert(string,insert,index):$string$index插入字符$insert
  • str_index(string,substring):返回$substring$string中第一个位置
  • str_slice(string,start_at,end_at = nil):返回从字符$string中第$start_at开始到$end_at结束的一个新字符串
  • to_upper_case(string):将字符$string变成大写
  • to_lower_case(string):将字符$string变成小写

新的@import功能

最后但并非最不重要的,他们计划重新整一个强大的@import功能。然而这并不是Sass3.3的功能,Chris打算在Sass4.0加入,除此之外,新版本也有一些新的功能:

  • @import-once
  • 导入常规的CSS文件
  • 命名空间
  • 当导入一个文件夹,会自动索引index.scss或者index.sass
  • 从一个文件夹中导入所有文件(可能吗?)

请注意这只是猜测。从开始讨论@import开始我就搜集了这个列表。顺便说一下,在没有请教Nathan或者Chris我就已经摆脱了提议。

只导入一次

如果你熟悉PHP或者其他程序语言,你可能知道include_once命令(一个类似的语法)。这个想法是为了一次只导入一个文件,而且只有一次。

在当前状态下,如果你两次导入相同的文件,会编译出来两次导入的文件内容,这样太不好了。

一个解决方案是Seanofw提出的一个小函数,将一个文件当为参数传入,然后检查文件名,确保文件只被导入一次。

$imported-once-files: ();

@function import-once($name) {
    @if index($imported-once-files, $name) {
        @return false;
    }
    $imported-once-files: append($imported-once-files, $name);
    @return true;
}

@if import-once("_SharedBaseStuff.scss") {
    /* ...declare stuff that will only be imported once... */
}

值得庆幸的是,新的@import功能将比这个函数更简单(详细信息请点击这里)。

导入常规的CSS文件

当你在一个项目中将CSS样式导入到SCSS或SASS样式中,是件烦人的事情,因为在Sass样式表中直接导航CSS样式,会完全崩溃。所以在Sass样式中能导入常规的CSS样式是很有意义的。

我想导入Normalize.css文件是最好的一个例子。当你使用@import "normalize"是没办法匹配一个常规的.css文件。因此你需要先将css文件转译成scss或者sass文件,这样非常的麻烦。

在新的@import中应该可以直接实现,详细信息请参考这里

导入默认号

这主要取决于你的结构,你可以在文件夹中管理你的文件。例如在一个helpers目录中放了一个mixin,每个文件夹只放一个文件。他提出了一个新的行为,通过index来导入一个文件夹。

你可以像下面这样操作:

/* Current way of doing */
@import "helpers/clearfix/index";

/* New way of doing */
@import "helpers/clearfix";

这绝对是一个主要特点, 不过我不明白为什么管理的是文件夹而不是直接文件,但我想应该也是可以的。详细信息请参考这里

从一个文件夹中导入所有文件

同样一个想法,增加一个新的特性,通过导入一个文件夹直接导入这个文件夹中所有文件。这也被称为"Sass Globbing",目前Chris Eppstein写了一个Sass的插件。(我想在Sass4.0会有这个功能)。

他将充许你像下面这样操作:

/* Import all files from folder helpers */
@import "library/helpers/*";

/* Import all folders from folder library */
@import "library/**/*";

但是请注意,文件被导入会是按字母顺序排列的,这可能会破坏你导入文件和你所需要的不一样。

命名空间

一个比较大的事情是,命名空间让CSS丢失。在Sass中一切都在一个全局范围。Kaelig提出一个讨论主题,建议遵循CSS的全局命名空间

不管怎么样,他们正在考虑通过命名空间来控制@import(详细信息请参考这里)。这样你就可以有一个更好控制你的文件和你的项目的方法。

因为这是一个很大的特性,还处理讨论当中,没有决定语法如何使用。我猜可能会像下面这样使用:

@import "file";
@import "file-2" as "Module";

.element {
    @extend file%placeholder;
    @include Module.mixin();
}

这个只是我的想法,可以不把他当一回事。如果您想了解这个问题,请参考这里

其他功能

大家先别急于离开哟,下面还有一些很有意思的东西。我在Sass代码分支中发现其他一些很酷的东西!

独特的ID

原来有一个unique-id()函数返回一个独特的随机标识符(运用于Sass的作用域)作为一个不带引号的字符串。基于我对Ruby代码的理解,它返加一个9个字符串长的字母数字。比如“u214ab34e”。

我还不太确定这种功能主要用途是什么,然而,这可能是一个方法,用来获得一个随机数,让我试试:

@function parse-unique-id($value) {
    $letters: a b c d e f g h i j k l m n o p q r s t u v w x y z;
    $value: unquote("");
    @for $i from 1 through str-length($value) {
        $letter: str-slice($value, $i, $i + 1);
        @if index($letter, $letters) == false {
            $value: str-insert($value, $letter, str-length($value) + 1);
        }
    }
    @return $value;
}
$number: parse-unique-id(unique-id());

如果你想测试这段代码,他是无法编译的,即使是最新的版本,因为它依赖于输入功能。基本上,它会检查unique-id()每个字符的值。如果这是一个字母,它会删除它。

他会给你一个0~9999999随机数,任何你想要的。

存在的检查

我发现几个功能,我认为主要由内部传动装置或者Sass库(详细请参考这里)。基本上他们允许你测试是否一个变量、函数或者是否存在当前状态。

  • variable_exists(named)
  • global_variable_exists(named)
  • function_exists(named)
  • mixin_exists(named)

似乎也存在一个feature_exists(named)函数,该函数是为了检查当前Sass运行时是否存在一个功能。我想它将用于未来的版本,用来检查一个给定的特性是否存在与否。

总结

好吧,我想说的就是这些,请记住大部分的东西都来自于 Github的问题讨论。没有日期或保证任何版本/特性宣布。

如果你对Sass的一些新特性感兴趣,我推荐你阅读官方的有关信息。

非常感谢您的阅读,下回再见!

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

如需转载烦请注明出处:

英文原文:http://davidwalsh.name/future-sass

中文译文:https://www.fedev.cn/preprocessor/future-sass.html

Air Max 90 Ultra BR