Sass中五个有用的代码片段

发布于 大漠

使用Sass,其中最喜欢的就是Sass的mixin和function功能。他们能自动化的重复使用一段CSS代码或功能以及更好的维护CSS。这些功能让人实在是折服。但我常常发现许多开发人员为一个简单的任务创建一个复杂的系统,比如管理一个字体堆栈或颜色方案。这些设置和使用都让人感到非常的繁琐。在这篇文章中,我将解释这些自动化实现的功能。

颜色

一个网站的配色方案是非常重要的。通常看到的一个方案就是设置一系列的变量。刚开始也认为这是一个很有效的,但这种方案也是直接得利用他们的代码。假设我们有五种颜色:$red$red-yellow$yellow$tan$brown。我知道你在想什么:"难道你不能记住这五种颜色值?"但这是一个非常小的配色方案。如果有多个红色什么?比如$red-2?五个不同红色?相反,我喜欢用一个颜色的函数。我知道我很有创造力。颜色一般需要三个参数:colorshadetransparent(如rgba)。

$color-stack:
    (group: orange, id: normal, color: #e67835),
    (group: orange, id: pale, color: #f8a878),
    (group: orange, id: dark, color: #ad490c),
    (group: blue, id: normal, color: #426682);

// Color  Function
@function color($group, $shade:normal, $transparency:1){
  @each $color in $color-stack{
    $c-group: map-get($color, group);
    $c-shade: map-get($color, id);
    @if($group == map-get($color, group) and $shade == map-get($color, id)){
      @return rgba(map-get($color, color), $transparency);
    }
  }
}

解释一下是怎么回事,定义了一个名为$color-stack的Sass Map。唯一要做的就是在这个Map中新增或删除一个颜色。这个Map包括了三个值:groupidcolor

  • **group:**组名,可以取你想要的名,比如说:orangeblue。这个字段不是独特的颜色
  • **id:**这是颜色唯一标识符。淡一点颜色叫pale,深一点的颜色叫dark,默认的normal。所以默认id的标识符定义为normal。这个域是独一无二的。不要重复在同一组中使用。
  • **color:**定义颜色值,采用的是十六进制

接下来定义了一个名为color的函数,这个函数会对$color-stack做遍历,直到匹配到groupid,然后调整对应的透明度。使用这个函数非常简单:

body{
  color: color(blue, normal,.8);
}
p{
  color: color(orange);
}
blockquote{
  color: color(blue);
  background: color(orange, pale,.4);
  border-color: color(orange, dark);
}

编译出来的CSS:

body {
  color: rgba(66, 102, 130, 0.8);
}
p {
  color: #e67835;
}
blockquote {
  color: #426682;
  background: rgba(248, 168, 120, 0.4);
  border-color: #ad490c;
}

**更新:**关于这个函数有一个常见的问题“我们为什么不使用$c-*?” 这是一个非常好的问题。为什么我使用color(),因为这只是出于我这自己的习惯。不管出于什么原因,对于我来说,写color()$c-*好。一般情况之下,我也喜欢把名称和描述分开。说实话,如果每次都在自己的项目中使用变量系统,你不会出太多的错,只要你保持简单的颜色名称、描述和组织。

Font Stack

字体堆栈是另一个问题,通常的解决办法是使用变量。在这种情况下,使用起来简单明了。但也有比较难搞的总是,当你使用第三方字体库,比如fonts.com,处理字体堆栈就会出现一些怪异的现象。那么如何为好呢?比如说你想使用“Brandon Grotesque”字体系列。font-weight200,它的font-family'Brandon Grot W01 Light';而font-weight700时,font-family'Brandon Grot W01 Bold'。这是一个问题?你可能会为更多字体设置一个混合宏,请不要这样做,我们只需要设计一个简单的混合宏。

$font-stack:
  (group: brandon, id: light, font: ('Brandon Grot W01 Light', san-serif ), weight: 200, style: normal),
  (group: brandon, id: light-italic, font: ('Brandon Grot W01 Light', san-serif ), weight: 200, style: italic),
  (group: brandon, id: regular, font: ('Brandon Grot W01-Regular', san-serif), weight: 400, style: normal),
  (group: brandon, id: regular-italic, font: ('Brandon Grot W01-Regular', san-serif), weight: 400, style: italic),
  (group: brandon, id: bold, font: ('Brandon Grot W01 Black', san-serif), weight: 700, style: normal),
  (group: brandon, id: bold-italic, font: ('Brandon Grot W01-Regular', san-serif), weight: 400, style: italic),
  (group: clarendon, id: regular, font: ('Clarendon LT W01', serif), weight: 200, style: normal),
  (group: code, id: regular, font: (monospace), weight: 400, style: normal);

// Breakpoint Mixin
@mixin font($group, $id:regular){
  @each $font in $font-stack{
    @if($group == map-get($font, group) and $id == map-get($font, id)){
      font-family: map-get($font, font);
      font-weight: map-get($font, weight);
      font-style: map-get($font, style);
    }
  }
}

你会注意到,和上例中的$color-stack类似,定义了一个Sass Map。这段代码和上例中的颜色功能非常类似,但有一些关键之处不同,下面简单介绍一下。

首先要处理的是$font-stack这个Map。在这个Map中包括了五个字段:

  • **group:**这是一组字体名。这是字体值,例如brandonclarendon或者serif
  • **id:**字体唯一标识符。例如boldlight-italicregular。其中regular是默认值。
  • **font:**这才是你想要的字体,他可以是一个map也可以是变量
  • **weight:**CSS中的font-weight,设置字体的粗细
  • **style:**CSS中的font-style,设置字体的样式

一旦你定义或调用mixin,这个mixin就会去遍历$font-stack,寻找匹配的groupid。一旦发现,将值返回给font-familyfont-weightfont-style

h1{
  @include font(brandon, light-italic);
}
p{
  @include font(brandon);
}
p i{
  @include font(brandon, regular-italic);
}
p b{
  @include font(brandon, bold);
}
blockquote{
  @include font(clarendon);
}
code{
  @include font(code);
}

编译出来的CSS

h1 {
  font-family: "Brandon Grot W01 Light", san-serif;
  font-weight: 200;
  font-style: italic;
}

p {
  font-family: "Brandon Grot W01-Regular", san-serif;
  font-weight: 400;
  font-style: normal;
}

p i {
  font-family: "Brandon Grot W01-Regular", san-serif;
  font-weight: 400;
  font-style: italic;
}

p b {
  font-family: "Brandon Grot W01 Black", san-serif;
  font-weight: 700;
  font-style: normal;
}

blockquote {
  font-family: "Clarendon LT W01", serif;
  font-weight: 200;
  font-style: normal;
}

code {
  font-family: monospace;
  font-weight: 400;
  font-style: normal;
}

就我个人而言,我喜欢以这种方式来处理我的字体。即使我的项目中不使用fonts.com,我也只需要使用这一个版本的mixin。

Media Queries

我想写一个最终版本的媒体查询混合宏。我就只要创建一个更易使用的混合宏。不管怎么说,这就是我想要的:

$media-stack:
  (group: tablet, id: general, rule: "only screen and (min-device-width: 700px)"),
  (group: small, id: general, rule: "only screen and(min-device-width: 1100px)"),
  (group: small, id: inbetween, rule: "only screen and(min-device-width: 1100px) and (max-device-width: 1400px)"),
  (group: large, id: general, rule: "only screen and(min-device-width: 1400px)"),
  (group: print, id: general, rule: "only print");
 
@mixin media($group, $id: general){
  @each $media in $media-stack{
    @if($group == map-get($media, group) and $id == map-get($media, id)){
      $rule: map-get($media, rule);
      @media #{$rule} {@content}
    }
  }
}

不用多说,你都注意到了$media-stack。就像这篇文章中其他几个:

  • **group:**这是媒体查询的组,这有很多个值可以使用,比如tabletsmall1400
  • **id:**媒体查询唯一标识符。这也是唯一的。如generalinbetweenexclude。默认的组一般为general
  • **rule:**这是你想要的媒体查询的实际规则。其值要用双引号括起来,否则Sass会报错

使用这个混合宏有两种方式。一个是自己调用,另一个是在嵌套中调用。我通常在嵌套中选择调用这个混合宏,这样会生成一个更小的CSS文件。

h1{
  color: #333;
  @include media(tablet){
    font-size: 1rem;
  };
  @include media(small, inbetween){
    font-size: 1.2rem;
  };
  @include media(small){
    color: #000;
  };
}

编译出来的CSS

h1 {
  color: #333;
}
@media only screen and (min-device-width: 700px) {
  h1 {
    font-size: 1rem;
  }
}
@media only screen and (min-device-width: 1100px) and (max-device-width: 1400px) {
  h1 {
    font-size: 1.2rem;
  }
}
@media only screen and (min-device-width: 1100px) {
  h1 {
    color: #000;
  }
}

更新:Mike Mai提出了一个很好的观点,通过内容来设置断点,因此在这个建议上,我对媒体查询的混合宏做了一个调整。

你会看到,我在Map中添加了一个新的组custom。这个用来自定义媒体查询,id设置为screen,因为你会发现,我只针对默认的屏幕。你还会发现一个名为$customRule的新规则。而这个$customRule可以让你添加你自己的规则。所以,你想要在360px分辨率屏幕下的h1都为蓝色,你就可以这样写:

h1{
  color: #333;
  @include media(tablet){
    font-size: 1rem;
  };
  @include media(small, inbetween){
    font-size: 1.2rem;
  };
  @include media(small){
    color: #000;
  };
  @include media(custom, screen, " (max-device-width: 360px)"){
    color: blue;
  };
}

编译出来的CSS

h1 {
  color: #333;
}
@media only screen and (min-device-width: 700px) {
  h1 {
    font-size: 1rem;
  }
}
@media only screen and (min-device-width: 1100px) and (max-device-width: 1400px) {
  h1 {
    font-size: 1.2rem;
  }
}
@media only screen and (min-device-width: 1100px) {
  h1 {
    color: #000;
  }
}
@media only screen and (max-device-width: 360px) {
  h1 {
    color: blue;
  }
}

你可能会问,你为什么不给每个都增加一个$customRule选项呢?其实是可以的,你完全可以为每个都添加一个$customRule

h1{
  color: #333;
  @include media(tablet, general, " and (min-device-pixel-ratio: 2)"){
    font-size: 1rem;
  };
  @include media(small, inbetween){
    font-size: 1.2rem;
  };
  @include media(small){
    color: #000;
  };
  @include media(custom, screen, "(max-device-width: 360px)"){
    color: blue;
  };
}

总结

这三个功能可以让你保持Sass代码清洁和更易维护。如果你有更好的建议或者你想说的,都可以在下面的评论中与我们一起分享。

本文根据@chdhmphry的《Useful Sass Snippets》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://hmphry.com/useful-sass-mixins