前言
SASS是最古老,也是最成熟的CSS預處理語言,誕生於2007年。有著比LESS更強大的功能。不過最開始的縮排式語法,並不能被廣大使用者接受,所以雖然出現很早但是普及卻不如LESS,但是隨著自身語法的改進和Ruby on Rails的大力推進,絕大多數人都開始選用SASS作為自己的前處理器開發利器。官網給出的介紹是:它是一門高於CSS的元語言,能用來編寫清晰且結構化的描述檔案樣式,有著比普通CSS更強大的功能。提供更簡潔、更優雅的語法,同時提供多種功能來建立可維護和管理的樣式表。
什麼是CSS前處理器
CSS 前處理器用一種專門的程式語言,為 CSS 增加了一些程式設計的特性,進行 Web 頁面樣式設計,然後再編譯成正常的 CSS 檔案,以供專案使用,特點是前處理器是一門單獨的語言,有變數、邏輯判斷、函式,還有,使用時,需要編譯成正常的CSS
CSS前處理器技術已經非常成熟,當然有許多不同的CSS前處理器,比如SASS/LESS/Stylus 等等,關於那種前處理器是最優秀的,各大技術論壇爭論紛紛。本文將要介紹的就是能夠讓絕大多數前端開發工程師滿意的一種:SASS
SASS 和 SCSS
兩者其實是同一種東西,我們平時都稱之為Sass,兩者不同之處有以下兩點
-
副檔名不同分別為
.sass
和.scss
-
語法書寫方式不同。SASS以嚴格縮排式語法來編寫,不包含大括號和分號,類似Jade;而SCSS的語法書寫則和CSS的語法書寫非常類似,舉個栗子
SASS語法 $font-stack: Helvetica, sans-serif //定義變數 $primary-color: #333 //定義變數 body font: 100% $font-stack color: $primary-color SCSS語法 $font-stack: Helvetica, sans-serif; $primary-color: #333; body { font: 100% $font-stack; color: $primary-color; } 兩者編譯出來的CSS檔案 body { font: 100% Helvetica, sans-serif; color: #333; } 複製程式碼
可見,Sass
和CSS
的書寫語法差別很大,而Sass
書寫則和CSS
幾乎一樣,所以這也是為什麼越來越多的前端開發使用Sass
中的SCSS方式來開發的原因
Sass的安裝
MAC系統
- brew install ruby
- sudo gem install sass
- sass -v
Window系統
開啟ruby 命令列
命令列輸入 gem install sass
複製程式碼
如果上面安裝失敗,可能是因為該安裝途徑已經被牆了,需要更換安裝的源,這裡我們使用淘寶的源,附上安裝步驟
Sass基礎
接下來所說的所有語法書寫格式都是以
.scss
格式
基本格式
以.scss
作為檔案字尾,程式碼在一組大括號內且結束處都有一個分號作為結尾,同樣的CSS程式碼
body {
font: 100% Helvetica, sans-serif;
color: #333;
}
複製程式碼
我們使用SCSS語法格式將上面重寫一下
$font-stack: Helvetica, sans-serif;
$primary-color: #333;
body {
font: 100% $font-stack;
color: $primary-color;
}
複製程式碼
編譯.scss檔案
Sass是一個前處理器,將編寫的.scss
檔案編譯成對應的.css
檔案,專案中使用的還是.css
為字尾的檔案。具體的編譯方式有三種:命令編譯、GUI編譯、自動化編譯
-
命令編譯:使用指令程式碼進行編譯
sass src/:out/
如 sass sass/:css/ 這條指令意味著把’sass’資料夾中的所有’.scss’檔案編譯成’.css’檔案,並把這些’.css’檔案放置到css目錄下。這樣做的缺點是隻能一次性編譯,每次更改後都需要重複編譯。
如果這樣做太麻煩的話,可以使用’watch’功能,watch功能會監視指定檔案的改動,自動執行編譯
sass --watch src/:out/
複製程式碼
-
GUI編譯:
推薦使用Koloa
-
自動化編譯:這裡推薦使用 gulp
var gulp = require('gulp'); var sass = require('gulp-ruby-sass'); gulp.task('sass', function () { gulp.sass('./scss/*.scss') .pipe(gulp.dest('./css')); }); gulp.task('watch', function() { gulp.watch('scss/*.scss', ['sass']); }); gulp.task('default', ['sass','watch']); 複製程式碼
-
常見編譯問題
- Sass不支援‘GBK’編碼,所以在建立檔案時就需要將編碼格式設定為’utf-8’
- 不建議在專案中的檔案路徑或者檔名中出現中文漢字
不同的輸出風格
Sass中編譯出來的樣式風格可以按照不同的風格進行顯示。主要包括如下幾種
- 巢狀式輸出 nested
- 展開式輸出 expanded
- 緊湊式輸出 compact
- 壓縮式輸出 compressed
具體的輸出方式通過編譯指令完成
sass --watch test.scss:test.css --style nested
複製程式碼
對於如下的css樣式,分別舉例四種輸出方式
nav {
ul {margin: 0;}
li { display: inline-block; }
a {display: block;}
}
複製程式碼
-
巢狀式輸出 nested
nav ul { margin: 0; } nav li { display: inline-block; } nav a { display: block;} 複製程式碼
-
展開式輸出 expanded(和nested類似,但是大括號獨佔一行)
nav ul { margin: 0; } nav li { display: inline-block; } nav a { display: block; } 複製程式碼
-
緊湊型輸出 compact
nav ul { margin: 0; } nav li { display: inline-block; } nav a { display: block;} 複製程式碼
-
壓縮性輸出 compressed
nav ul{margin:0;padding:0;}nav li{display:inline-block}nav a{display:block;} 複製程式碼
SCSS 語法
變數
- 宣告變數
Sass中變數包含三部分:$、變數名稱、變數值,如
$width: 300px
複製程式碼
-
變數型別
-
普通變數
$fontSize: 12px; body{ font-size: $fontSize; } 複製程式碼
-
預設變數:僅需要在值得後面加上 !default
$baseLineHeight:1.5 !default; body{ line-height: $baseLineHeight; } 複製程式碼
-
類似於JavaScript中的短路賦值 var onePoint = req.query.from || ‘China’;
變數的呼叫
直接在需要賦值的地方使用$ 變數名就可以完成呼叫
作用域
分為全域性作用域和區域性作用域
$color: orange !default;//定義全域性變數
.block {
color: $color;//呼叫全域性變數,orange
}
em {
$color: red;//定義區域性變數
a {
color: $color;//呼叫區域性變數,red
}
}
複製程式碼
混合巨集
使用混合巨集可以自定義重複利用的而元件,關鍵字是 @mixin
。在混合巨集中,我們可以自定義程式碼的樣式,新增判斷邏輯等等
-
混合巨集的宣告
不帶引數的混合巨集
@mixin border-radius { -webkit-border-radius: 5px; border-radius: 5px; } 複製程式碼
帶引數的混合巨集:入參如果不存在使用預設的
5px
。這個5px
可以是頁面的預設屬性,而特殊的border-radius
則可以在呼叫是通過入參控制@mixin border-radius($radius:5px){ -webkit-border-radius: $radius; border-radius: $radius; } 複製程式碼
-
呼叫混合巨集
呼叫不帶引數的混合巨集(上文中定義的)
button { @include border-radius; } 複製程式碼
呼叫帶引數的混合巨集
button { @include border-radius(3px); } 複製程式碼
混合巨集的不足
混合巨集可以解決重複程式碼塊的問題,但是也有不足。最大的不足之處在於混合巨集會生成冗餘的程式碼塊,比如在不同的地方呼叫一個相同的混合巨集時。
@mixin border-radius{
-webkit-border-radius: 3px;
border-radius: 3px;
}
.box {
@include border-radius;
margin-bottom: 5px;
}
.btn {
@include border-radius;
}
複製程式碼
生成的CSS內容如下
.box {
-webkit-border-radius: 3px;
border-radius: 3px;
margin-bottom: 5px;
}
.btn {
-webkit-border-radius: 3px;
border-radius: 3px;
}
複製程式碼
可以看出兩個地方呼叫混合巨集,兩個地方都出現了混合巨集的程式碼內容,並沒有只能的將相同的程式碼進行合併成如下的樣式。
.box .btn{
-webkit-border-radius: 3px;
border-radius: 3px;
}
.box {
margin-bottom: 5px;
}
複製程式碼
@extend
繼承
CSS原本就有繼承機制的,內部元素預設會繼承外部元素的某些屬性。Sass中也有繼承這麼一說,通過@extend
來繼承已經存在的程式碼塊。
.btn {
border: 1px solid #ccc;
padding: 6px 10px;
font-size: 14px;
}
.btn-primary {
background-color: #f36;
color: #fff;
@extend .btn;
}
.btn-second {
background-color: orange;
color: #fff;
@extend .btn;
}
複製程式碼
編譯後
.btn, .btn-primary, .btn-second {
border: 1px solid #ccc;
padding: 6px 10px;
font-size: 14px;
}
.btn-primary {
background-color: #f36;
color: #fff;
}
.btn-second {
background-clor: orange;
color: #fff;
}
複製程式碼
從示例程式碼中我們可以看出,在Sass中的繼承,可以繼承類樣式中的所有程式碼,而編譯出的CSS會合併到一起,形成組合選擇器.btn, .btn-primary, .btn-second {}
的形式
混合巨集定義了一個可以支援引數傳遞的複用程式碼塊,但是程式碼塊本身必不能直接作為樣式;繼承作為雖然不能提供引數傳遞的複用程式碼塊,但是父類本身可以作為樣式~
佔位符
Sass
中的佔位符 %placeholder
類似於繼承中的基類,可以通過@extend
繼承選中基類中的程式碼。但是不同的是通過佔位符宣告的程式碼,如果不被@extend
的話,不會產生任何程式碼,所以和繼承是有差別的,舉個栗子。
%mt5 {
margin-top: 5px;
}
%pt5{
padding-top: 5px;
}
.btn {
@extend %mt5;
@extend %pt5;
}
.block {
@extend %mt5;
span {
@extend %pt5;
}
}
複製程式碼
從輸出中可以看到,佔位符的輸出中不包含佔位符本身
.btn, .block {
margin-top: 5px;
}
.btn, .block span {
padding-top: 5px;
}
複製程式碼
相同的實現,我們再來看一下繼承
.mt5 {
margin-top: 5px;
}
.pt5{
padding-top: 5px;
}
.btn {
@extend .mt5;
@extend .pt5;
}
.block {
@extend .mt5;
span {
@extend .pt5;
}
}
繼承的輸出中包含了基類本身
.mt5, .btn, .block {
margin-top: 5px;
}
.pt5, .btn, .block span {
padding-top: 5px;
}
複製程式碼
是不是感覺佔位符很像繼承和
@mixin
的混合體。不支援引數傳遞的複用程式碼塊(繼承),本身不出現在輸出中(@mixin
)
混合巨集 VS 繼承 VS 佔位符
什麼時候該使用它們中的某一個呢?在這裡總結一下如何使用這幾個容易讓人弄混的概念
- 混合巨集:不會自動合併相同的樣式檔案,會造成程式碼冗餘,但是可以傳遞引數
- 繼承:會合並相同的程式碼,通過組合選擇器輸出,但是不能傳遞引數
- 佔位符:編譯出來的程式碼和使用繼承基本上是一樣的,自是不會在程式碼中出現佔位符本身
佔位符是獨立定義的,不呼叫的時候是不會在程式碼充產生任何程式碼。而繼承首先要保證有一個基類的存在,不管呼叫與不呼叫,積累的樣式都會出現在編譯出來的額CSS程式碼中
下面的程式碼幫助大家記憶三者的區別
//=========
//混合巨集寫法
@mixin mt($var){
margin-top: $var;
}
.block {
@include mt(4px);
span {
display:block;
@include mt(3px);
}
}
.header {
color: orange;
@include mt(5px);
span{
display:block;
@include mt(5px);
}
}
//混合巨集寫法輸出
.block { margin-top: 4px; }
.block span { display: block; margin-top: 3px; }
.header { color: orange; margin-top: 5px; }
.header span { display: block; margin-top: 5px; }
//=========
//繼承寫法
.mt{
margin-top: 5px;
}
.block {
@extend .mt;
span {
display:block;
@extend .mt;
}
}
.header {
color: orange;
@extend .mt;
span{
display:block;
@extend .mt;
}
}
// 繼承寫法輸出
.mt, .block, .block span, .header, .header span { margin-top: 5px; }
.block span { display: block; }
.header { color: orange; }
.header span { display: block; }
//=========
//佔位符
%mt{
margin-top: 5px;
}
.block {
@extend %mt;
span {
display:block;
@extend %mt;
}
}
.header {
color: orange;
@extend %mt;
span{
display:block;
@extend %mt;
}
}
//佔位符寫法輸出
.block, .block span, .header, .header span { margin-top: 5px; }
.block span { display: block; }
.header { color: orange; }
.header span { display: block; }
複製程式碼