Sass基础语法

日期:2015-07-06 10:02:47

Sass的SCSS语法是CSS3语法的一个超集。这就意味着如果你会读写CSS,就已经知道了如何读写基本的Sass。

在CSS的基础之上,Sass添加了新特性和新语法,让你能够用更少量的代码更加清楚地表示更多的样式。添加某些Sass特性是为了让那些已掌握CSS但可能从未接触过Sass的人,能轻松地理解样式。

文件后缀名

Sass文件就是普通的文本文件,里面可以直接使用CSS语法。文件后缀名是.scss,意思为Sassy CSS。

导入

Sass的导入(@import)规则和CSS的有所不同,编译时会将@import的scss文件合并进来只生成一个CSS文件。但是如果你在Sass文件中导入css文件如@import 'reset.css',那效果跟普通CSS导入样式文件一样,导入的css文件不会合并到编译后的文件中,而是以@import方式存在。

所有的Sass导入文件都可以忽略后缀名.scss。一般来说基础的文件命名方法以_开头,如_mixin.scss。这种文件在导入的时候可以不写下划线,可写成@import "mixin"。

要导入sass文件test.scss的内容:

//test.scss
.test {
  font-size: 14px;
  color: #333;
}

需要导入样式的demo.scss的文件内容:

@import "reset.css";
@import "test";
body {
  background-color: #f5f5f5;
}

编译后的demo.scss文件内容:

@import url(reset.css);
.test {
  font-size: 14px;
  color: #333;
}
body {
  background-color: #f5f5f5;
}

根据上面的代码可以看出,demo.scss编译后,reset.css继续保持import的方式,而test.scss则被整合进来了。

编译

上面的demo.scss文件是怎么输出生成CSS文件的呢?这就要用的Sass的编译命令(sass文件夹存放的是sass文件,css文件夹存放的是css文件):

sass sass/demo.scss css/demo.css

这样就可以在css文件夹看到编译后的demo.css文件了,这是用到单文件转换命令。

还可以用到单文件监听命令,这样就不用修改保存一次就手动输入一次编译命令了:

sass --watch sass/demo.scss:css/demo.css

文件夹监听命令,监听文件夹内所有sass文件改动,并编译:

sass --watch sass:css

生成 source map,方便调试

sass --watch sass:css --sourcemap

--sourcemap表示开启sourcemap调试。开启sourcemap调试后,会生成一个后缀名为.css.map文件。这样就可以像调试CSS一样在浏览器调试scss文件了。


更多命令请查看帮助:

sass -h

注释

Sass有两种注释方式,一种是标准的CSS注释方式/* */,另一种则是//双斜杆形式的单行注释,不过这种单行注释不会被转译出来。

两种注释比较:

//我是双斜杠单行注释,不会被编译出来
/* 我是标准CSS注释,我可以被编译出来 */
body {
  background-color: #f5f5f5;
}

编译后:

/* 我是标准CSS注释,我可以被编译出来 */
body {
  background-color: #f5f5f5;
}

这里有一个坑,代码若有中文编译Sass,文件出现Syntax error: Invalid GBK character报错,解决方法如下:

在C:\Ruby22-x64\lib\ruby\gems\2.2.0\gems\sass-3.4.15\lib\sass\engine.rb文件里面加入

Encoding.default_external = Encoding.find('utf-8')

放在所有的require XXXX 之后即可。最后在scss文件头部启用编码声明:@charset "utf-8"; //必须设置了这个才能编译有中文的注释

 变量

Sass的变量必须是$开头,后面紧跟变量名,而变量值和变量名之间就需要使用冒号(:)分隔开(就像CSS属性设置一样),如果值后面加上!default则表示默认值。

普通变量

普通变量定以后可以在全局范围内使用。

//sass style
$font-size: 14px;
p {
  font-size: $font-size;
}

//css style
p {
  font-size: 14px;
}

默认变量

Sass的默认变量仅需要在值后面加上!default即可。

//sass style
$font-size: 14px !default;
$font-size: 16px;
p {
  font-size: $font-size;
}

//css style
p{
font-size:16px; 
}

Sass的默认变量一般是用来设置默认值,然后根据需求来覆盖的,覆盖的方式也很简单,只需要在默认变量之前重新声明下变量即可。

可以看出现在编译后的font-size为16px,而不是我们默认的14px。默认变量的价值在进行组件化开发的时候会非常有用。

特殊变量

一般我们定义的变量都为属性值,可直接使用,但是如果变量作为属性或在某些特殊情况下等则必须要以#{$variables}形式使用。

//sass style
$border-direction: left;
.border-#{$border-direction} {
  border-#{$border-direction}: 5px solid #eee;
}

//css style 
.border-left {
  border-left: 5px solid #eee;
}

多值变量

多值变量分为list类型和map类型,简单来说list类型有点像js中的数组,而map类型有点像js中的对象。

List类型

list数据可通过空格,逗号或小括号分隔多个值,可用nth($var,$index)取值。关于list数据操作还有很多其他函数如length($list),join($list1,$list2,[$separator]),append($list,$value,[$separator])等,具体可参考sass Functions(搜索List Functions即可)。

//sass style
//一维数据
$px: 10px 9px 8px 7px;
//二维数据
$px1: 5px 10px, 0 auto;
$px2: (5px 10px) (0 auto);
div {
  margin: nth($px1, 2);
  padding: nth($px, 1);
}

//css style
div {
  margin: 0 auto;
  padding: 10px;
}

 map类型

map数据以key和value成对出现,其中value又可以是list。格式为:$map: (key1: value1, key2: value2, key3: value3);。可通过map-get($map,$key)取值。关于map数据还有很多其他函数如map-merge($map1,$map2),map-keys($map),map-values($map)等,具体可参考sass Functions(搜索Map Functions即可).

//sass style
$map:( dribble: #ea4c89, facebook: #3b5998, Github: #171515, google: #db4437, twitter: #55acee);
.twitter {
    background-color: map-get($map, twitter);
}
.facebook {
    background-color: map-get($map, facebook);
}

//css style
.twitter {
  background-color: #55acee;
}
.facebook {
  background-color: #3b5998;
}

嵌套(Nesting)

sass的嵌套包括两种:一种是选择器的嵌套;另一种是属性的嵌套。我们一般说起或用到的都是选择器的嵌套。

选择器嵌套

选择器嵌套指的是在一个选择器中嵌套另一个选择器来实现继承,从而增强了sass文件的结构性和可读性。在选择器嵌套中,可以使用&表示父元素选择器。

//sass style
.list-wrap {
    background: #333;
    font-size: 14px;
    li {
        float: left;
        a {
            color: #fff;
            &:hover {
                color: #f60;
            }
        }
    }
}

//css style 
.list-wrap {
  background: #333;
  font-size: 14px;
}
.list-wrap li {
  float: left;
}
.list-wrap li a {
  color: #fff;
}
.list-wrap li a:hover {
  color: #f60;
}

属性嵌套 

属性嵌套指的是有些属性拥有同一个开始单词,如border-width,border-color都是以border开头。拿个官网的实例看下:

//sass style
.border {
    border: {
        width: 5px;
        right: {
            style: solid;
            color: #eee;
        }
    }
}

//css style
.border {
  border-width: 5px;
  border-right-style: solid;
  border-right-color: #eee;
}

好吧,实际开发中估计没人会这么写。

 父选择器的标识符&

在使用嵌套规则时,父选择器能对于嵌套规则如何解开提供更好的控制。它就是一个简单的&符号,且可以放在任何一个选择器可出现的地方。

//sass style
a {
  color: blue;
  &:hover {
    color: red;
  }
  &.active {
    color: orange;
  }
}

//css style
a {
  color: blue;
}
a:hover {
  color: red;
}
a.active {
  color: orange;
}

@at-root

Sass3.3.0中新增的功能,用来跳出选择器嵌套的。默认所有的嵌套,继承所有上级选择器,但有了这个就可以跳出所有上级选择器。

//sass style 
.at-root {
  background-color: #666;
  @at-root .item {
    color: red;
  }
}

//css style
.at-root {
  background-color: #666;
}
.item {
  color: red;
}

好吧,好像没什么特别的。

下面来看一个更实用的例子:

//sass style
.content {
  @at-root #{&}-header {
    color: red;
  }
  @at-root #{&}-content {
    color: blue;
  }
}

//css style
.content-header {
  color: red;
}
.content-content {
  color: blue;
}

到了这里,你是否体会到@at-root在BEM中是具有多大的优势了吧。

混合器(mixin)

Sass中使用@mixin声明混合,可以传递参数,参数名以$符号开始,多个参数以逗号分开,也可以给参数设置默认值。声明的@mixin通过@include来调用。

无参数mixin

//sass style
@mixin no-bullets {//创建mixin
  list-style: none;
  li {
    list-style-image: none;
    list-style-type: none;
    margin-left: 0px;
  }
}
.ul-style {
  @include no-bullets;//调用mixin
}

//css style
.ul-style {
  list-style: none;
}
.ul-style li {
  list-style-image: none;
  list-style-type: none;
  margin-left: 0px;
}

有参数mixin

//sass style
@mixin link-colors($normal, $hover, $visited) {
  color: $normal;
  &:hover {
    color: $hover;
  }
  &:visited {
    color: $visited;
  }
}
a {
  @include link-colors(#333, #666, #999);//调用并传参,如果无参数会报错。
}

//css style
a {
  color: #333;
}
a:hover {
  color: #666;
}
a:visited {
  color: #999;
}

多组值参数mixin

如果一个参数可以有多组值,如box-shadow、transition等,那么参数则需要在变量后加三个点表示,如$variables...。

//sass style
//box-shadow可以有多组值,所以在变量参数后面添加...
@mixin box-shadow($shadow...) {
  moz-box-shadow: $shadow;
  -webkit-box-shadow: $shadow;
  box-shadow: $shadow;
}
.box-shadow {
  @include box-shadow(1px 1px 5px #333, 0 1px 3px #666, 0 2px 5px #999);
}

//css style
.box-shadow {
  moz-box-shadow: 1px 1px 5px #333, 0 1px 3px #666, 0 2px 5px #999;
  -webkit-box-shadow: 1px 1px 5px #333, 0 1px 3px #666, 0 2px 5px #999;
  box-shadow: 1px 1px 5px #333, 0 1px 3px #666, 0 2px 5px #999;
}

 @content

@content在Sass3.2.0中引入,可以用来解决CSS3的@media等带来的问题。它可以使@mixin接受一整块样式,接受的样式从@content开始。

//sass style
@mixin max-screen($res) {
  @media only screen and (max-width: $res) {
    @content;
  }
}
@include max-screen(480px) {
  body {
    color: red;
  }
}

//css style
@media only screen and (max-width: 480px) {
  body {
    color: red;
  }
}

PS:@mixin通过@include调用后解析出来的样式是以拷贝形式存在的,而下面的继承则是以联合声明的方式存在的,所以从3.2.0版本以后,建议传递参数的用@mixin,而非传递参数类的使用下面的继承%。

继承

使用Sass的时候,最后一个减少重复的主要特性就是选择器继承。选择器继承是说一个选择器可以继承为另一个选择器定义的所有样式。这个通过@extend语法实现。

//sass style
.hint {
  font-size: 14px;
  color: #333;
}
.error {
  @extend .hint;
  border-left: 3px solid red;
}

//css style
.hint, .error {
  font-size: 14px;
  color: #333;
}
.error {
  border-left: 3px solid red;
}

 占位选择器%

从Sass 3.2.0以后就可以定义占位选择器%。这种选择器的优势在于:如果不调用则不会有任何多余的css文件,避免了以前在一些基础的文件中预定义了很多基础的样式,然后实际应用中不管是否使用了@extend去继承相应的样式,都会解析出来所有的样式。占位选择器以%标识定义,通过@extend调用。

//sass style
%font {
  border: 1px solid #999;
  font-size: 14px;
}
.text {
  @extend %font;
  background: #eee;
}
.text1 {
  @extend %font;
  background: #f5f5f5;
}

//css style
.text, .text1 {
  border: 1px solid #999;
  font-size: 14px;
}
.text {
  background: #eee;
}
.text1 {
  background: #f5f5f5;
}

占位选择器的出现,使CSS文件更加简练可控,没有多余。所以可以用其定义一些基础的样式文件,然后根据需要调用产生相应的CSS。

函数

Sass定义了很多函数可供使用,当然你也可以自己定义函数,以@fuction开始。Sass的官方函数链接为:sass fuction,实际项目中我们使用最多的应该是颜色函数,而颜色函数中又以lighten减淡和darken加深为最,其调用方法为lighten($color,$amount)和darken($color,$amount),它们的第一个参数都是颜色值,第二个参数都是百分比。

//sass style
// rgb($red,$green,$blue):根据红、绿、蓝三个值创建一个颜色
// rgba($color,$alpha) //将一个Hex颜色转换成rgba颜色
a {
  color: rgb(250, 250, 250);
  background-color: lighten(#ccc, 10%);
  &:hover {
    color: rgba(red, 0.5);
    background-color: darken(#999, 50%);
  }
}

//css style
a {
  color: #fafafa;
  background-color: #e6e6e6;
}
a:hover {
  color: rgba(255, 0, 0, 0.5);
  background-color: #1a1a1a;
}

运算

Sass具有运算的特性,可以对数值型的Value(如:数字、颜色、变量等)进行加减乘除四则运算。请注意运算符前后请留一个空格,不然会出错。

$baseFontSize: 14px !default;
$baseLineHeight: 1.5 !default;
$baseGap: $baseFontSize * $baseLineHeight !default;
$halfBaseGap: $baseGap / 2 !default;
$samllFontSize: $baseFontSize - 2px !default;

条件判断及循环

@if

这个@if就不用解释吧,一看都知道是条件判断。这个东西对于浏览器兼容这块可以出不少力量;然后对于写一些基础的scss,控制样式的输出也是一大利器;当然还有很多很多了,反正是个必备的好东西就是了。先来个简单的例子吧:

//sass style
$lie7: true !default;
$type: twitter !default;
//inline-block
//ie6-7 *display: inline;*zoom:1;
@mixin inline-block { //@if的mixin实例
  display: inline-block;
  @if $lie7 {
    *display: inline;
    *zoom: 1;
  }
}
@mixin color { //@else的mixin实例
  @if $type == twitter {
    color: blue;
  }
  @else if $type == google {
    color: red;
  }
  @else if $type == fackbook {
    color: black;
  }
  @else {
    color: orange;
  }
}
.dib {
  @include inline-block;
  @include color;
}

//css style
.dib {
  display: inline-block;
  *display: inline;
  *zoom: 1;
  color: blue;
}

三目判断

语法为:if($condition, $if_true, $if_false) 。三个参数分别表示:条件,条件为真的值,条件为假的值。

if(true, 1px, 2px) => 1px
if(false, 1px, 2px) => 2px

@for循环

for循环有两种形式,分别为:@for $var from through 和@for $var from to 。$i表示变量,start表示起始值,end表示结束值,这两个的区别是关键字through表示包括end这个数,而to则不包括end这个数。

@for应用在网格系统生成各个格子class的代码:

//sass style
// class span1-$gridColumns
// span的class循环输出,通过变量$gridSpanSwitch来控制是否输出
//-----------------------------------------------------
$gridColumns: 12 !default;
$gridcolumnWidth: 60px !default;
$gridGutter: 20px !default;
 
%span-base {
  float: left;
  margin-left: $gridGutter / 2;
  margin-right: $gridGutter / 2;
}
@for $i from 1 through $gridColumns {
  .span#{$i} {
    @extend %span-base;
    width: ($gridcolumnWidth + $gridGutter) * $i - $gridGutter;
  }
}

//css style
.span1, .span2, .span3, .span4, .span5, .span6, .span7, .span8, .span9, .span10, .span11, .span12 {
  float: left;
  margin-left: 10px;
  margin-right: 10px;
}
.span1 {
  width: 60px;
}
.span2 {
  width: 140px;
}
.span3 {
  width: 220px;
}
.span4 {
  width: 300px;
}
.span5 {
  width: 380px;
}
.span6 {
  width: 460px;
}
.span7 {
  width: 540px;
}
.span8 {
  width: 620px;
}
.span9 {
  width: 700px;
}
.span10 {
  width: 780px;
}
.span11 {
  width: 860px;
}
.span12 {
  width: 940px;
}

这样一循环,比一个个写爽多了吧,因为float和margin什么的都一样,所以我们使用占位选择器申明,然后@extend调用,那样就是组合申明了。

@each循环

语法为:@each $var in <list or map>。其中$var表示变量,而list和map表示list类型数据和map类型数据。Sass 3.3.0新加入了多字段循环和map数据循环。

//sass style
$animal-list: puma, sea-slug, egret, salamander;
@each $animal in $animal-list {
  .#{$animal}-icon {
    background-image: url("/images/#{$animal}.png");
  }
}

//css style
.puma-icon {
  background-image: url('/images/puma.png'); 
}
.sea-slug-icon {
  background-image: url('/images/sea-slug.png'); 
}
.egret-icon {
  background-image: url('/images/egret.png'); 
}
.salamander-icon {
  background-image: url('/images/salamander.png'); 
}

多个字段list数据循环

//sass style
$btnColorClass: (primary #0078E7 #fff) (blue #00A3CF #fff) (orange #F47837 #fff) !default;
@mixin btn-color($bgColor: #e6e6e6, $textColor: #333) {
  color: $textColor;
  background-color: $bgColor;
  border: 1px solid darken($bgColor, 5%);
  border-color: lighten($bgColor, 2%) darken($bgColor, 5%) darken($bgColor, 5%) lighten($bgColor, 2%);
  &:hover {
    background-color: darken($bgColor, 5%);
    color: $textColor;
  }
}
@each $colorClass in $btnColorClass {
  $class: nth($colorClass, 1);
  $bgColor: nth($colorClass, 2);
  $textColor: nth($colorClass, 3);
  .btn-#{$class} {
    @include btn-color($bgColor, $textColor);
  }
}

//css style
.btn-primary {
  color: #fff;
  background-color: #0078E7;
  border: 1px solid #006bce;
  border-color: #007df1 #006bce #006bce #007df1;
}
.btn-primary:hover {
  background-color: #006bce;
  color: #fff;
}
.btn-blue {
  color: #fff;
  background-color: #00A3CF;
  border: 1px solid #008fb6;
  border-color: #00abd9 #008fb6 #008fb6 #00abd9;
}
.btn-blue:hover {
  background-color: #008fb6;
  color: #fff;
}
.btn-orange {
  color: #fff;
  background-color: #F47837;
  border: 1px solid #f3681f;
  border-color: #f57f41 #f3681f #f3681f #f57f41;
}
.btn-orange:hover {
  background-color: #f3681f;
  color: #fff;
}

多个字段map数据循环

//sass style
$headings: (h1: 2em, h2: 1.5em, h3: 1.2em);
@each $header, $size in $headings {
  #{$header} {
    font-size: $size;
  }
}

//css style
h1 {
  font-size: 2em;
}
h2 {
  font-size: 1.5em;
}
h3 {
  font-size: 1.2em;
}