如何编写自定义Sass函数

如果您构建过不少网站,可能已注意到可以在一个项目中轻易的复制代码然后跨项目应用。反复复制相同的代码会浪费时间和增加错误出现的可能性。在Sass之前的系列中,我曾说mixins是样式重用和编写 DRYer代码的一个选择。Functions是实现相同功能的另一个方法。

最近几个月我一直在讲Sass的数据类型、运算符和函数。我们讲过了numbersstringscolorscolors againlistslists again, 和maps。过去几周我讲到了控制指令。今天是该系列的最后一部分,我想以@function指令和如何编写自定义函数结课。

如何创建和使用自定义函数

函数是可返回一个Sass任何数据类型单一值的代码块。创建自定义函数需要两个Sass指令,@function@return。前者创建函数,后者表明了函数将返回的值。

@function function-name($args) { 
    @return value-to-be-returned;
}

传递到函数中的参数是可选的,尽管你会经常使用它们。通常Sass函数会使用传递过去的参数进行运算,也可能是一些所有函数都可以访问的全局变量

由于历史原因,函数名可交替使用破折号或下划线,故function-namefunction_name是相同的函数,可使用破折号或下划线调用函数,无论命名时使用的是哪个。

上述代码只显示了一行返回一个值的代码,但大多数函数所做的并不仅限于此,于是@return指令将会作为函数的最后一行。

记得只有一个值返回,这个值可以是任何的数据类型,返回的可以是数字9,字符串"I am a string",或者一种数据结构,比如listmap,里面包含您想要的任何值。

要使用函数您需要提供函数名和参数,放在想要返回值显示的位置。

p { 
  font-size: function-name($args); 
}
p { 
  font-size: function_name($args); 
}

重申,这两个都会调用同一个函数。可以假定该函数将计算pxem值,并返回作为段落的font-size

正像我所说的,函数可以访问任何全局定义的变量。下个示例中我创建了两个全局变量,$total$col$total表示网格的总列数,$col表示一个3列宽的网格字段

$total: 8; 
$col: 3
@function column-width() { 
  @return percentage($col/$total); 
}

这个函数没有任何参数。它用$col除以$total,使用内置percentage函数将结果在返回之前变成百分值。

我们可在想要返回值显示的位置通过添加函数名来调用函数。因为这个函数不带参数,调用时无需传参。

.col-3 { 
   width: column-width(); 
}

函数完成运算后代码被编译为:

.col-3 { width: 37.5%; }

这样编写的函数用处不大,因为不得不硬编码总列数和网格字段的大小作为全局变量。一个更有用的方案是将这些变量当成参数传递,下面我们重写这个函数。

@function column-width($col, $total) { 
  @return percentage($col/$total); 
}

该函数现在接收参数,我们必须在函数调用期间传值过去,尽管我们可以重用这个函数并用不同的参数调用它。

.col-3 { 
  width: column-width(3, 8); 
}
.col-5 { 
  width: column-width(5, 8); 
}

会编译成:

.col-3 { 
    width: 37.5%; 
}
.col-5 { 
   width: 62.5%; 
}

关键字参数

您可能已经注意到,在前面的实例中,我按照它们在函数中列出的顺序传递参数。这是必须的,除非您使用关键字。

可以使用key:value的格式传递键/值对。

.col-3 {  
   width: column-width($col: 3, $total: 8);  
}

如果包含了键名,则不必按它们在函数中列出的顺序来排列。

.col-3 {  
    width: column-width($total: 8, $col: 3);  
}

尽管函数是以先$col$total的顺序列出,通过使用每个值之前的关键字,函数知道哪个对应哪个。

您还可以在创建函数时声明参数的默认值。这里我修改了函数,所以总列数的默认值为8

@function column-width($col, $total:8) {  
     @return percentage($col/$total);  
}
.col-3 {  
     width: column-width(3);  
}

上面的代码只传递了一个值到函数。该函数会使用我没有传递的那个参数的默认值,仍然会编译成:

.col-3 {  
     width: 37.5%;  
}

您可通过传递带有或者不带关键字的参数来覆盖默认值。

.col-3 {  
      width: column-width(3, 9);  
}

.col-4 {  
     width: column-width($col:3, $total:12);  
}

一个更实际的例子

到目前为止并没有哪个例子很实用。我写它们是为了解释某事物如何运作。下面我们来写一些更实用的代码。

这里我将全局变量$total设置为8,然后重写了前面例子中的函数,使用全局变量,而不是将总列数作为参数传递。

最后我使用了一个从1运行到$total值的for循环。在循环里面,计数器$i成为了类名的一部分,并且类的宽度是通过将$i的值传递给函数而生成的。

$total: 8;

@function column-width($col) {  
     @return percentage($col/$total);  
}

@for $i from 1 through $total {  
     .col-#/{$i/} { width: column-width($i) };  
}

Sass代码编译为:

.col-1 { width: 12.5%; }  
.col-2 { width: 25%; }  
.col-3 { width: 37.5%; }  
.col-4 { width: 50%; }  
.col-5 { width: 62.5%; }  
.col-6 { width: 75%; }  
.col-7 { width: 87.5%; }  
.col-8 { width: 100%; }

如果您决定使用12列或9列或4列而不是8列布局,您只需要更改$total的值。自定义函数和@for循环将完成其余操作。

可变参数

mixins一样,函数可以通过在参数名称后面使用3个点(非省略号)来接收可变参数。该函数将从传递给它的变量参数创建一个列表。

在下面的示例中我创建了一个函数,它接收一个名为$index的参数和一个名为$widths...的变量参数。

@function column-width($index, $widths...){  
      @return nth($widths, $index);  
}

该函数将使用内置的nth函数找到$widths中下标为$index的值。当调用该函数时,我传递给它一个索引值和一系列的百分比宽度。

.col-3 {  
    width: column-width(3, 25%, 50%, 75%, 100%);  
}

因为75%是索引为3的值,所以代码编译为:

.col-3 {  
    width: 75%;  
}

坦白说这不是特别有用的函数,因为如果仅仅是设置宽度,不调用函数设置会更容易。虽然可变参数在mixins中有用,可以添加多个盒子阴影,但很难想象它们在函数中有什么用处。但这仍然是你可以做的事,我认为值得分享。

给您的函数名添加前缀

值得一提的是,给您的函数名添加一个前缀不失为一个好主意,这样可避免与内置函数或您可能正在使用的库产生命名冲突。

不难想象其他人创建了一个与我在示例中使用的函数名称冲突的column-width函数。将其命名为vanseo-column-width可能更好,因为第三方函数不太可能会使用相同的前缀。

Function还是Mixin

因为 Sass functions 和 Sass mixins是相似的,您可能纳闷应该使用哪个。虽然类似,但它们有一个重要的区别,这表明了在什么时候使用哪个是最佳的。

两者之间的主要区别是,Sass代码的mixins输出行将直接编译为CSS样式,而函数则返回一个可以作为CSS属性或可传递给另一个function或mixin的值。

说实话,您可以将每个函数都改写为混合宏的形式,反之亦然,但每个都有清晰的用例。

想要直接输出样式,使用mixin;想执行返回值的运算,使用function。例如,确定响应容器的百分比宽度公式可能看起来很熟悉

target / context = result

因为这是一个可能在样式表中执行多次的运算,适合使用function,您可以传递target和context的值从而得到返回的结果。

总结

Functions是一种将可重用的代码移动到单独包的方法。它们与mixins相似,两者的不同点在于输出。 Functions返回一个值而mixins输出代码。如果您知道怎么使用其中一个,那么使用另一个对您来说也不难。

Sass数据类型,运算符和函数系列已经到了尾声。希望在系列的最后您能理解我为什么花时间讲每种不同的数据类型。除颜色外,其他的数据类型在function和mixins中更有用。

本文根据@Steven Bradley的《How To Write Your Own Custom Sass Functions》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://vanseodesign.com/css/custom-sass-functions/

出处:http://www.w3cplus.com/preprocessor/custom-sass-functions.html