對於一個從後台轉到前端的web開發者來說,最大的麻煩就是寫CSS,了解CSS的人都知道,它可以開發網頁樣式,但是沒法用它編程,感覺耦合性相當的高,如果想要方便以後維護,只能逐句修改甚至重寫相當一部分的CSS。隨著後台人員大量的湧入前端這個產業,CSS又煥發了新的春天,人們開始為CSS加入程式設計元素,也就是「CSS預處理器」。它的基本想法就是用專門的程式語言,進行網頁樣式設計,然後再編譯成正常的CSS檔。以下我們結合官方文件和阮一峰老師的用法指南,再次系統的總結Sass的主要用法。
Sass是Ruby語言寫的,我們在安裝Sass之前必須先安裝Ruby,安裝Ruby的過程就不再贅述,安裝好Ruby後可以直接在命令列(windows在cmd中)輸入下面的命令
<code>gem install sass </code>
Sass文件就是普通的文字文件,後綴名有.sass和.scss兩種。 後綴名為.sass的文件編碼風格不需要添加大括號,但需要處理縮排等操作,如下
<code>* margin:0; padding:0; </code>
後綴名為.scss的檔案編碼風格偏向正常的CSS風格如下:
<code>*{ margin:0; padding:0; } </code>
Sass官方都會對兩者風格平行更新,所以喜歡哪種風格還是看個人的愛好,由於本人偏向於.scss文件後綴,所以下面的例子都會基於.scss文件風格。
下面的指令,可以在螢幕上顯示.scss檔轉換的css(假設檔名為test)
<code>sass test.scss </code>
如果要把.scss檔直接轉換成css文件,後面需要再跟.css的檔名
<code>sass test.scss test.css </code>
Sass提供了四種編譯風格的選項
<code>* nested: 嵌套缩进的css的代码,默认 * expanded:没有缩进、扩展的css代码 * compact:简介格式的css代码 * compressed:压缩后的css代码 </code>
我們可以用以下命令切換編譯風格
<code>sass --style compressed test.scss test.css </code>
我們也可以讓Sass監聽某個檔案或目錄,一旦原始檔發生變動,就自動產生編譯後的版本
<code>// watch a file sass --watch test.scss:test.css // watch a direcoty sass --watch app/sass:public/stylesheets </code>
如果有使用webStrom開發的同學可以添加File Watchers,但是我感覺不如開啟整個目錄監聽的好,有一點需要注意的就是不同的批處理對應不同的的後綴名文件即sass.bat對應.sass檔、 scss.bat對應.scss檔
Sass的導入(@import)規則和CSS的有所不同,讓我們回顧一下CSS@import導入的缺點:CSS在@import一個文件的時候,它不會立即導入,只有在引用它的那個css檔案下載、解析之後,瀏覽器才會知道還有另外一個css需要下載,這時才去下載,然後下載後開始解析、構建render tree等一系列操作,從而導致css無法並行下載。但Sass的導入(@import),編譯時會將@import的scss檔合併進來只產生一個CSS檔。但如果你在sass檔中導入css檔如@import 'reset.css',效果跟普通CSS導入樣式檔一樣,導入的css檔不會合併到編譯後的檔中,但會以@import方式存在。
所有的sass導入檔案都可以忽略後綴名.scss。一般來說基礎的檔案命名方法以開頭,如mixin.scss。這種文件在導入的時候可以不寫下劃線,可寫成@import "mixin"。
被導入sass檔a.scss:
<code>//a.scss //------------------------------- body { background: #eee; } </code>
需要導入樣式的sass檔b.scss:
<code>@import "reset.css"; @import "a"; p{ background: #0982c1; } </code>
轉譯出來的b.css樣式:
<code>@import "reset.css"; body { background: #eee; } p{ background: #0982c1; } </code>
根據上面的程式碼可以看出,b.scss編譯後,reset.css繼續保持import的方式,而a.scss則被整合進來了。
sass有兩種註釋方式,一種是標準的css註釋方式/* */,另一種則是//雙斜桿形式的單行註釋,不過這種單行註釋不會被轉譯出來。 標準的css註解
<code>/* *我是css的标准注释 *设置body内距 */ body{ padding:5px; } </code>
雙斜桿單行註解 單行註解跟JavaScript語言中的註解一樣,使用又斜線(//),但單行註解不會輸入到CSS中。
<code>//我是双斜杠表示的单行注释 //设置body内距 body{ padding:5px; //5px } </code>
sass的變數必須是$開頭,後面跟著變數名,而變數值和變數名之間就需要使用冒號(:)分隔開(就像CSS屬性設定一樣),如果值後面加上!default則表示預設值。
定義之後可以在全域範圍內使用。
<code>//sass style //------------------------------- $fontSize: 12px; body{ font-size:$fontSize; } //css style //------------------------------- body{ font-size:12px; } </code>
sass的預設變數只需要在值後面加上!default即可。
<code>//sass style //------------------------------- $baseLineHeight: 1.5 !default; body{ line-height: $baseLineHeight; } //css style //------------------------------- body{ line-height:1.5; } </code>
sass的預設變數一般是用來設定預設值,然後根據需求來覆蓋的,覆蓋的方式也很簡單,只需要在預設變數之前重新聲明下變數即可
<code>//sass style //------------------------------- $baseLineHeight: 2; $baseLineHeight: 1.5 !default; body{ line-height: $baseLineHeight; } //css style //------------------------------- body{ line-height:2; } </code>
可以看出現在編譯後的line-height為2,而不是我們預設的1.5。預設變數的價值在進行組件化開發的時候會非常有用。
一般我們定義的變數都是屬性值,可直接使用,但是如果變數作為屬性或在某些特殊情況下等則必須以#{$variables}形式使用。
<code>//sass style //------------------------------- $borderDirection: top !default; $baseFontSize: 12px !default; $baseLineHeight: 1.5 !default; //应用于class和属性 .border-#{$borderDirection}{ border-#{$borderDirection}:1px solid #ccc; } //应用于复杂的属性值 body{ font:#{$baseFontSize}/#{$baseLineHeight}; } //css style //------------------------------- .border-top{ border-top:1px solid #ccc; } body { font: 12px/1.5; } </code>
多值變數分為list型別和map型,簡單來說list型別有點像js中的數組,而map型別有點像js中的物件。
list数据可通过空格,逗号或小括号分隔多个值,可用nth($var,$index)取值。关于list数据操作还有很多其他函数如length($list),join($list1,$list2,[$separator]),append($list,$value,[$separator])等,具体可参考sass Functions(搜索List Functions即可) 定义
<code>//一维数据 $px: 5px 10px 20px 30px; //二维数据,相当于js中的二维数组 $px: 5px 10px, 20px 30px; $px: (5px 10px) (20px 30px); </code>
使用
<code>//sass style //------------------------------- $linkColor: #08c #333 !default;//第一个值为默认值,第二个鼠标滑过值 a{ color:nth($linkColor,1); &:hover{ color:nth($linkColor,2); } } //css style //------------------------------- a{ color:#08c; } a:hover{ color:#333; } </code>
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即可) 定义
<code>$heading: (h1: 2em, h2: 1.5em, h3: 1.2em); </code>
使用
<code>//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; } </code>
sass的嵌套包括两种:一种是选择器的嵌套;另一种是属性的嵌套。我们一般说起或用到的都是选择器的嵌套。
所谓选择器嵌套指的是在一个选择器中嵌套另一个选择器来实现继承,从而增强了sass文件的结构性和可读性。 在选择器嵌套中,可以使用&表示父元素选择器
<code>//sass style //------------------------------- #top_nav{ line-height: 40px; text-transform: capitalize; background-color:#333; li{ float:left; } a{ display: block; padding: 0 10px; color: #fff; &:hover{ color:#ddd; } } } //css style //------------------------------- #top_nav{ line-height: 40px; text-transform: capitalize; background-color:#333; } #top_nav li{ float:left; } #top_nav a{ display: block; padding: 0 10px; color: #fff; } #top_nav a:hover{ color:#ddd; } </code>
所谓属性嵌套指的是有些属性拥有同一个开始单词,如border-width,border-color都是以border开头。拿个官网的实例看下:
<code>//sass style //------------------------------- .fakeshadow { border: { style: solid; left: { width: 4px; color: #888; } right: { width: 2px; color: #ccc; } } } //css style //------------------------------- .fakeshadow { border-style: solid; border-left-width: 4px; border-left-color: #888; border-right-width: 2px; border-right-color: #ccc; } </code>
sass中使用@mixin声明混合,可以传递参数,参数名以$符号开始,多个参数以逗号分开,也可以给参数设置默认值。声明的@mixin通过@include来调用。
<code>//sass style //------------------------------- @mixin center-block { margin-left:auto; margin-right:auto; } .demo{ @include center-block; } //css style //------------------------------- .demo{ margin-left:auto; margin-right:auto; } </code>
<code>//sass style //------------------------------- @mixin opacity($opacity:50) { opacity: $opacity / 100; filter: alpha(opacity=$opacity); } //css style //------------------------------- .opacity{ @include opacity; //参数使用默认值 } .opacity-80{ @include opacity(80); //传递参数 } </code>
调用时可直接传入值,如@include传入参数的个数小于@mixin定义参数的个数,则按照顺序表示,后面不足的使用默认值,如不足的没有默认值则报错。除此之外还可以选择性的传入参数,使用参数名与值同时传入。
<code>//sass style //------------------------------- @mixin horizontal-line($border:1px dashed #ccc, $padding:10px){ border-bottom:$border; padding-top:$padding; padding-bottom:$padding; } .imgtext-h li{ @include horizontal-line(1px solid #ccc); } .imgtext-h--product li{ @include horizontal-line($padding:15px); } //css style //------------------------------- .imgtext-h li { border-bottom: 1px solid #cccccc; padding-top: 10px; padding-bottom: 10px; } .imgtext-h--product li { border-bottom: 1px dashed #cccccc; padding-top: 15px; padding-bottom: 15px; } </code>
如果一个参数可以有多组值,如box-shadow、transition等,那么参数则需要在变量后加三个点表示,如$variables...。
<code>//sass style //------------------------------- //box-shadow可以有多组值,所以在变量参数后面添加... @mixin box-shadow($shadow...) { -webkit-box-shadow:$shadow; box-shadow:$shadow; } .box{ border:1px solid #ccc; @include box-shadow(0 2px 2px rgba(0,0,0,.3),0 3px 3px rgba(0,0,0,.3),0 4px 4px rgba(0,0,0,.3)); } //css style //------------------------------- .box{ border:1px solid #ccc; -webkit-box-shadow:0 2px 2px rgba(0,0,0,.3),0 3px 3px rgba(0,0,0,.3),0 4px 4px rgba(0,0,0,.3); box-shadow:0 2px 2px rgba(0,0,0,.3),0 3px 3px rgba(0,0,0,.3),0 4px 4px rgba(0,0,0,.3); } </code>
@content在sass3.2.0中引入,可以用来解决css3的@media等带来的问题。它可以使@mixin接受一整块样式,接受的样式从@content开始。
<code>//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 } } </code>
sass中,选择器继承可以让选择器继承另一个选择器的所有样式,并联合声明。使用选择器的继承,要使用关键词@extend,后面紧跟需要继承的选择器。
<code>//sass style //------------------------------- h1{ border: 4px solid #ff9aa9; } .speaker{ @extend h1; border-width: 2px; } //css style //------------------------------- h1,.speaker{ border: 4px solid #ff9aa9; } .speaker{ border-width: 2px; } </code>
从sass 3.2.0以后就可以定义占位选择器%。这种选择器的优势在于:如果不调用则不会有任何多余的css文件,避免了以前在一些基础的文件中预定义了很多基础的样式,然后实际应用中不管是否使用了@extend去继承相应的样式,都会解析出来所有的样式。占位选择器以%标识定义,通过@extend调用。
<code>//sass style //------------------------------- %ir{ color: transparent; text-shadow: none; background-color: transparent; border: 0; } %clearfix{ @if $lte7 { *zoom: 1; } &:before, &:after { content: ""; display: table; font: 0/0 a; } &:after { clear: both; } } #header{ h1{ @extend %ir; width:300px; } } .ir{ @extend %ir; } //css style //------------------------------- #header h1, .ir{ color: transparent; text-shadow: none; background-color: transparent; border: 0; } #header h1{ width:300px; } </code>
如上代码,定义了两个占位选择器%ir和%clearfix,其中%clearfix这个没有调用,所以解析出来的css样式也就没有clearfix部分。占位选择器的出现,使css文件更加简练可控,没有多余。所以可以用其定义一些基础的样式文件,然后根据需要调用产生相应的css。
ps:在@media中暂时不能@extend @media外的代码片段,以后将会可以。
sass定义了很多函数可供使用,当然你也可以自己定义函数,以@fuction开始。实际项目中我们使用最多的应该是颜色函数,而颜色函数中又以lighten减淡和darken加深为最,其调用方法为lighten($color,$amount)和darken($color,$amount),它们的第一个参数都是颜色值,第二个参数都是百分比。
<code>//sass style //------------------------------- $baseFontSize: 10px !default; $gray: #ccc !defualt; // pixels to rems @function pxToRem($px) { @return $px / $baseFontSize * 1rem; } body{ font-size:$baseFontSize; color:lighten($gray,10%); } .test{ font-size:pxToRem(16px); color:darken($gray,10%); } //css style //------------------------------- body{ font-size:10px; color:#E6E6E6; } .test{ font-size:1.6rem; color:#B3B3B3; } </code>
sass具有运算的特性,可以对数值型的Value(如:数字、颜色、变量等)进行加减乘除四则运算。请注意运算符前后请留一个空格,不然会出错。
<code>$baseFontSize: 14px !default; $baseLineHeight: 1.5 !default; $baseGap: $baseFontSize * $baseLineHeight !default; $halfBaseGap: $baseGap / 2 !default; $samllFontSize: $baseFontSize - 2px !default; //grid $_columns: 12 !default; // Total number of columns $_column-width: 60px !default; // Width of a single column $_gutter: 20px !default; // Width of the gutter $_gridsystem-width: $_columns * ($_column-width + $_gutter); //grid system width </code>
@if可一个条件单独使用,也可以和@else结合多条件使用
<code>//sass style //------------------------------- $lte7: true; $type: monster; .ib{ display:inline-block; @if $lte7 { *display:inline; *zoom:1; } } p { @if $type == ocean { color: blue; } @else if $type == matador { color: red; } @else if $type == monster { color: green; } @else { color: black; } } //css style //------------------------------- .ib{ display:inline-block; *display:inline; *zoom:1; } p { color: green; } </code>
语法为:if($condition, $iftrue, $iffalse) 。三个参数分别表示:条件,条件为真的值,条件为假的值。
<code>if(true, 1px, 2px) => 1px if(false, 1px, 2px) => 2px </code>
for循环有两种形式,分别为:@for $var from through 和@for $var from to 。$i表示变量,start表示起始值,end表示结束值,这两个的区别是关键字through表示包括end这个数,而to则不包括end这个数。
<code>//sass style //------------------------------- @for $i from 1 through 3 { .item-#{$i} { width: 2em * $i; } } //css style //------------------------------- .item-1 { width: 2em; } .item-2 { width: 4em; } .item-3 { width: 6em; } </code>
语法为:@each $var in 。其中$var表示变量,而list和map表示list类型数据和map类型数据。sass 3.3.0新加入了多字段循环和map数据循环。
<code>//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'); } </code>
<code>//sass style //------------------------------- $animal-data: (puma, black, default),(sea-slug, blue, pointer),(egret, white, move); @each $animal, $color, $cursor in $animal-data { .#{$animal}-icon { background-image: url('/images/#{$animal}.png'); border: 2px solid $color; cursor: $cursor; } } //css style //------------------------------- .puma-icon { background-image: url('/images/puma.png'); border: 2px solid black; cursor: default; } .sea-slug-icon { background-image: url('/images/sea-slug.png'); border: 2px solid blue; cursor: pointer; } .egret-icon { background-image: url('/images/egret.png'); border: 2px solid white; cursor: move; } </code>
<code>//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; } </code>
(完)