使用Sass,其中最喜欢的就是Sass的mixin和function功能。他们能自动化的重复使用一段CSS代码或功能以及更好的维护CSS。这些功能让人实在是折服。但我常常发现许多开发人员为一个简单的任务创建一个复杂的系统,比如管理一个字体堆栈或颜色方案。这些设置和使用都让人感到非常的繁琐。在这篇文章中,我将解释这些自动化实现的功能。
颜色
一个网站的配色方案是非常重要的。通常看到的一个方案就是设置一系列的变量。刚开始也认为这是一个很有效的,但这种方案也是直接得利用他们的代码。假设我们有五种颜色:$red
、$red-yellow
、$yellow
、$tan
和$brown
。我知道你在想什么:"难道你不能记住这五种颜色值?"但这是一个非常小的配色方案。如果有多个红色什么?比如$red-2
?五个不同红色?相反,我喜欢用一个颜色的函数。我知道我很有创造力。颜色一般需要三个参数:color
、shade
和transparent
(如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包括了三个值:group
、id
和color
。
- group:组名,可以取你想要的名,比如说:
orange
、blue
。这个字段不是独特的颜色 - id:这是颜色唯一标识符。淡一点颜色叫
pale
,深一点的颜色叫dark
,默认的normal
。所以默认id
的标识符定义为normal
。这个域是独一无二的。不要重复在同一组中使用。 - color:定义颜色值,采用的是十六进制
接下来定义了一个名为color
的函数,这个函数会对$color-stack
做遍历,直到匹配到group
和id
,然后调整对应的透明度。使用这个函数非常简单:
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-weight
是200
,它的font-family
是'Brandon Grot W01 Light'
;而font-weight
为700
时,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:这是一组字体名。这是字体值,例如
brandon
、clarendon
或者serif
- id:字体唯一标识符。例如
bold
、light-italic
、regular
。其中regular
是默认值。 - font:这才是你想要的字体,他可以是一个map也可以是变量
- weight:CSS中的
font-weight
,设置字体的粗细 - style:CSS中的
font-style
,设置字体的样式
一旦你定义或调用mixin,这个mixin就会去遍历$font-stack
,寻找匹配的group
和id
。一旦发现,将值返回给font-family
、font-weight
、font-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:这是媒体查询的组,这有很多个值可以使用,比如
tablet
、small
和1400
- id:媒体查询唯一标识符。这也是唯一的。如
general
、inbetween
和exclude
。默认的组一般为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。
如需转载,烦请注明出处:http://www.w3cplus.com/preprocessor/5-useful-sass-snippets.html