1. 程式人生 > >sass入門篇

sass入門篇

第1章:Sass簡介

1-1.什麼是 CSS 前處理器?

“CSS 前處理器用一種專門的程式語言,進行 Web 頁面樣式設計,然後再編譯成正常的 CSS 檔案,以供專案使用。CSS 前處理器為 CSS 增加一些程式設計的特性,無需考慮瀏覽器的相容性問題”,例如你可以在 CSS 中使用變數簡單的邏輯程式函式等等在程式語言中的一些基本特性,可以讓你的 CSS 更加簡潔適應性更強可讀性更佳更易於程式碼的維護等諸多好處。

在眾多優秀的 CSS 前處理器語言中就屬 SassLESS 和 Stylus 最優秀,討論的也多,對比的也多。

1-2.什麼是Sass?

Sass 是一門高於 CSS 的元語言,它能用來清晰地、結構化地描述檔案樣式,有著比普通 CSS 更加強大的功能。
Sass 能夠提供更簡潔、更優雅的語法,同時提供多種功能來建立可維護和管理的樣式表。

1-3.Sass和SCSS有什麼區別?

Sass 和 SCSS 其實是同一種東西,我們平時都稱之為 Sass,兩者之間不同之處有以下兩點:

(1)副檔名不同,Sass 是以“.sass”字尾為副檔名,而 SCSS 是以“.scss”字尾為副檔名

(2)語法書寫方式不同,Sass 是以嚴格的縮排式語法規則來書寫,不帶大括號({})和分號(;),而 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;
}

1-4.Sass/SCSS 和純 CSS 寫法差很多嗎?

Sass 和 CSS 寫法有差別:

       由於 Sass 是基於 Ruby 寫出來,所以其延續了 Ruby 的書寫規範(Ruby,一種簡單快捷的

面向物件(面向物件程式設計)指令碼語言)。

       在書寫 Sass 時不帶有大括號和分號,其主要是依靠嚴格的縮排方式來控制的。如:

Sass寫法:

body
  color: #fff
  background: #f36

而在 CSS 我們是這樣書寫:

body{
  color:#fff;
  background:#f36;
}

SCSS 和 CSS 寫法無差別:

SCSS 和 CSS 寫法無差別,這也是 Sass 後來越來越受大眾喜歡原因之一。簡單點說,把你現有的“.css”檔案直接修改成“.scss”即可使用。

第三章:Sass語法格式

3-1.Sass 語法格式

這裡說的 Sass 語法是 Sass 的最初語法格式,他是通過 tab 鍵控制縮排的一種語法規則,而且這種縮排要求非常嚴格。另外其不帶有任何的分號和大括號。常常把這種格式稱為 Sass 老版本,其檔名以“.sass”為副檔名。
來看一個 Sass 語法格式的簡單示例。假設我們有一段這樣的 CSS 程式碼:

body {
  font: 100% Helvetica, sans-serif;
  color: #333;
}

現在用 Sass 的語法格式來編寫:

$font-stack: Helvetica, sans-serif
$primary-color: #333

body
  font: 100% $font-stack
  color: $primary-color

在整個 Sass 程式碼中,我們沒看到類似 CSS 中的大括號和分號。
注:這種語法格式對於前端人員都不太容易接受,而且容易出錯。

二、SCSS語法格式

SCSS 是 Sass 的新語法格式,從外形上來判斷他和 CSS 長得幾乎是一模一樣,程式碼都包裹在一對大括號裡,並且末尾結束處都有一個分號。其檔名格式常常以“.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 的語法格式,他們的功能都是一樣的,不同的是其書寫格式和副檔名不同,來看一個簡單的對比圖:


正因為如此,有不少同學使用 Sass 新的語法規則,而副檔名依舊使用的是“.sass”,這也就造成血案了,編譯時說編譯不出來。在此特別提醒新同學:“.sass”只能使用 Sass 老語法規則(縮排規則),“.scss”使用的是 Sass 的新語法規則,也就是 SCSS 語法規則(類似 CSS 語法格式)。

特別提醒:本系列教程後面採用的語法格式都將使用的是 SCSS 語法格式。

3.2 Sass編譯

常常有人會問,使用 Sass 進行開發,那麼是不是直接通過“<link>”引用“.scss”或“.sass”檔案呢?

那麼這裡告訴大家,在專案中還是引用“.css”檔案,Sass 只不過是做為一個預處理工具,提前幫你做事情,只有你需要時候,他才有攻效。

這樣一來,也就有了這章需要介紹的內容—— Sass 的編譯。因為 Sass 開發之後,要讓 Web 頁面能呼叫 Sass 寫好的東西,就得有這麼一個過程,這個過程就稱之為 Sass 編譯過程。Sass 的編譯有多種方法:

  • 命令編譯
  • GUI工具編譯
  • 自動化編譯

(1)命令編譯是指使用你電腦中的命令終端,通過輸入 Sass 指令來編譯 Sass。

(2)或許你會說,我一直討厭使用命令來做事情,我喜歡那種能看得到的介面操作。那麼你可以考慮使用 GUI 介面工具來對 Sass 進行編譯。

目前較為流行的主要有:

相比之下,我比較推薦使用以下兩個:

  • CodeKit (http://www.w3cplus.com/preprocessor/sass-gui-tool-codekit.html)
    (3)

    自動化編譯

    喜歡自動化研究的同學,應該都知道 Grunt 和 Gulp 這兩個東東。如果您正在使用其中的任何一種,那麼你也可以通過他們來配置 Sass 的編譯。這裡僅列出兩個示例程式碼(具體情況要根據您的專案環境來做一定的修改,不建議生搬硬套,容易發生命案,呵呵。

    1、Grunt 配置 Sass 編譯的示例程式碼

    module.exports = function(grunt) {
        grunt.initConfig({
            pkg: grunt.file.readJSON('package.json'),
            sass: {
                dist: {
                    files: {
                        'style/style.css' : 'sass/style.scss'
                    }
                }
            },
            watch: {
                css: {
                    files: '**/*.scss',
                    tasks: ['sass']
                }
            }
        });
        grunt.loadNpmTasks('grunt-contrib-sass');
        grunt.loadNpmTasks('grunt-contrib-watch');
        grunt.registerTask('default',['watch']);
    }

    2、Gulp 配置 Sass 編譯的示例程式碼

    var gulp = require('gulp');
    var sass = require('gulp-sass');
    
    gulp.task('sass', function () {
        gulp.src('./scss/*.scss')
            .pipe(sass())
            .pipe(gulp.dest('./css'));
    });
    
    gulp.task('watch', function() {
        gulp.watch('scss/*.scss', ['sass']);
    });
    
    gulp.task('default', ['sass','watch']);
    

    3-7.[Sass]不同樣式風格的輸出方法

    眾所周知,每個人編寫的 CSS 樣式風格都不一樣,有的喜歡將所有樣式程式碼都寫在同一行,而有的喜歡將樣式分行書寫。在 Sass 中編譯出來的樣式風格也可以按不同的樣式風格顯示。其主要包括以下幾種樣式風格:

  • 巢狀輸出方式 nested
  • 展開輸出方式 expanded  
  • 緊湊輸出方式 compact 
  • 壓縮輸出方式 compressed

    3-8.

    [Sass]巢狀輸出方式 nested

    1、巢狀輸出方式 nested

    Sass 提供了一種巢狀顯示 CSS 檔案的方式。例如

    nav {
      ul {
        margin: 0;
        padding: 0;
        list-style: none;
      }
    
      li { display: inline-block; }
    
      a {
        display: block;
        padding: 6px 12px;
        text-decoration: none;
      }
    }

    在編譯的時候帶上引數“ --style nested”:

    sass --watch test.scss:test.css --style nested

    編譯出來的 CSS 樣式風格:

    nav ul {
      margin: 0;
      padding: 0;
      list-style: none; }
    nav li {
      display: inline-block; }
    nav a {
      display: block;
      padding: 6px 12px;
      text-decoration: none; }

    如下圖所示:


3-9.[Sass]展開輸出方式 expanded

2、巢狀輸出方式 expanded

nav {
  ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  li { display: inline-block; }

  a {
    display: block;
    padding: 6px 12px;
    text-decoration: none;
  }
}

在編譯的時候帶上引數“ --style expanded”:

sass --watch test.scss:test.css --style expanded

這個輸出的 CSS 樣式風格和 nested 類似,只是大括號在另起一行,同樣上面的程式碼,編譯出來:

nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
}
nav li {
  display: inline-block;
}
nav a {
  display: block;
  padding: 6px 12px;
  text-decoration: none;
}


3-10.[Sass]緊湊輸出方式 compact

2、巢狀輸出方式 compact

nav {
  ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  li { display: inline-block; }

  a {
    display: block;
    padding: 6px 12px;
    text-decoration: none;
  }
}

在編譯的時候帶上引數“ --style compact”:

sass --watch test.scss:test.css --style compact

該方式適合那些喜歡單行 CSS 樣式格式的朋友,編譯後的程式碼如下:

nav ul { margin: 0; padding: 0; list-style: none; }
nav li { display: inline-block; }
nav a { display: block; padding: 6px 12px; text-decoration: none; }

3-11.[Sass]壓縮輸出方式 compressed

2、壓縮輸出方式 compressed

nav {
  ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  li { display: inline-block; }

  a {
    display: block;
    padding: 6px 12px;
    text-decoration: none;
  }
}

在編譯的時候帶上引數“ --style compressed”:

sass --watch test.scss:test.css --style compressed

壓縮輸出方式會去掉標準的 Sass 和 CSS 註釋及空格。也就是壓縮好的 CSS 程式碼樣式風格:

nav ul{margin:0;padding:0;list-style:none}nav li{display:inline-block}nav a{display:block;padding:6px 12px;text-decoration:none}

編譯出來的CSS樣式風格的選擇完全是個人喜好問題,可以根據自己喜歡的風格選擇引數。

一段時間之後,你實際上就不再需要寫 CSS 程式碼了,只用寫 Sass 程式碼。在這種情況下,你只需要設定輸出格式為壓縮格式,知道輸出的 CSS 程式碼可以直接使用即可。

3-12.Sass 的除錯


(單擊可放大)

Sass 除錯一直以來都是一件頭痛的事情,使用 Sass 的同學都希望能在瀏覽器中直接除錯 Sass 檔案,能找到對應的行數。值得慶幸的是,現在實現並不是一件難事,只要你的瀏覽器支援“sourcemap”功能即可。早一點的版本,需要在編譯的時候新增“--sourcemap”  引數:

sass --watch --scss --sourcemap style.scss:style.css

在 Sass3.3 版本之上(我測試使用的版本是 3.4.7),不需要新增這個引數也可以:

sass --watch style.scss:style.css

在命令終端,你將看到一個資訊:

>>> Change detected to: style.scss
  write style.css
  write style.css.map

這時你就可以像前面展示的 gif 圖一樣,除錯你的 Sass 程式碼。

 第四章:Sass的基本特性-基礎

4-1.[Sass]宣告變數

定義變數的語法:

在有些程式語言中(如,JavaScript)宣告變數都是使用關鍵詞“var”開頭,但是在 Sass 不使用這個關鍵詞,而是使用大家都喜歡的美元符號“$”開頭。我想用一張圖來解釋,我一直堅信,一圖勝千言萬語:

上圖非常清楚告訴了大家,Sass 的變數包括三個部分:

  1. 宣告變數的符號“$”
  2. 變數名稱
  3. 賦予變數的值

來看一個簡單的示例,假設你的按鈕顏色可以給其宣告幾個變數:

$brand-primary : darken(#428bca, 6.5%) !default; // #337ab7
$btn-primary-color : #fff !default;
$btn-primary-bg : $brand-primary !default;
$btn-primary-border : darken($btn-primary-bg, 5%) !default;

如果值後面加上!default則表示預設值。

注:瞭解 Bootstrap 的 Sass 版本的同學,就一眼能看出,上面的示例程式碼是 Bootstrap 定義 primarybutton 的顏色。

4-2.[Sass]普通變數與預設變數

普通變數

定義之後可以在全域性範圍內使用。

$fontSize: 12px;
body{
    font-size:$fontSize;
}

編譯後的css程式碼:

body{
    font-size:12px;
}

預設變數

sass 的預設變數僅需要在值後面加上 !default 即可。

$baseLineHeight:1.5 !default;
body{
    line-height: $baseLineHeight; 
}

編譯後的css程式碼:

body{
    line-height:1.5;
}


sass 的預設變數一般是用來設定預設值,然後根據需求來覆蓋的,覆蓋的方式也很簡單,只需要在預設變數之前重新宣告下變數即可。
 

$baseLineHeight: 2;
$baseLineHeight: 1.5 !default;
body{
    line-height: $baseLineHeight; 
}

編譯後的css程式碼:

body{
    line-height:2;
}
可以看出現在編譯後的 line-height 為 2,而不是我們預設的 1.5。預設變數的價值在進行元件化開發的時候會非常有用。

4-3.[Sass]變數的呼叫

在 Sass 中聲明瞭變數之後,就可以在需要的地方呼叫變數。呼叫變數的方法也非常的簡單。

比如在定義了變數

$brand-primary : darken(#428bca, 6.5%) !default; // #337ab7
$btn-primary-color: #fff !default;
$btn-primary-bg : $brand-primary !default;
$btn-primary-border : darken($btn-primary-bg, 5%) !default;


在按鈕 button 中呼叫,可以按下面的方式呼叫

.btn-primary {
   background-color: $btn-primary-bg;
   color: $btn-primary-color;
   border: 1px solid $btn-primary-border;
}

編譯出來的CSS:

.btn-primary {
  background-color: #337ab7;
  color: #fff;
  border: 1px solid #2e6da4;
}

補充知識點:

sass定義了顏色函式,分為三大類RGB,HSL和Opacity。

darken()屬於HSL類,HSL為:H-色相 S-飽和度 L-亮度。

使用方法:darken(原色,亮度值)

亮度值取0~1之間。

編譯成css時,會自動轉換成相應的色號。

例如本題中darken(#428bca, 6.5%)編譯後的色號為#337ab7。

4-4.[Sass]區域性變數和全域性變數

全域性變數與區域性變數

先來看一下程式碼例子:

//SCSS
$color: orange !default;//定義全域性變數(在選擇器、函式、混合巨集...的外面定義的變數為全域性變數)
.block {
  color: $color;//呼叫全域性變數
}
em {
  $color: red;//定義區域性變數
  a {
    color: $color;//呼叫區域性變數
  }
}
span {
  color: $color;//呼叫全域性變數
}

css 的結果:

//CSS
.block {
  color: orange;
}
em a {
  color: red;
}
span {
  color: orange;
}

上面的示例演示可以得知,在元素內部定義的變數不會影響其他元素。如此可以簡單的理解成,全域性變數就是定義在元素外面的變數,如下程式碼:

$color:orange !default;

$color 就是一個全域性變數,而定義在元素內部的變數,比如 $color:red; 是一個區域性變數

除此之外,Sass 現在還提供一個 !global 引數。!global 和 !default 對於定義變數都是很有幫助的。我們之後將會詳細介紹這兩個引數的使用以及其功能。

全域性變數的影子

當在區域性範圍(選擇器內、函式內、混合巨集內...)宣告一個已經存在於全域性範圍內的變數時,區域性變數就成為了全域性變數的影子。基本上,區域性變數只會在區域性範圍內覆蓋全域性變數

上面例子中的 em 選擇器內的變數 $color 就是一個全域性變數的影子。

//SCSS
$color: orange !default;//定義全域性變數
.block {
  color: $color;//呼叫全域性變數
}
em {
  $color: red;//定義區域性變數(全域性變數 $color 的影子)
  a {
    color: $color;//呼叫區域性變數
  }
}

什麼時候宣告變數?

我的建議,建立變數只適用於感覺確有必要的情況下。不要為了某些駭客行為而宣告新變數,這絲毫沒有作用。只有滿足所有下述標準時方可建立新變數:

  1. 該值至少重複出現了兩次;
  2. 該值至少可能會被更新一次;
  3. 該值所有的表現都與變數有關(非巧合)。

基本上,沒有理由宣告一個永遠不需要更新或者只在單一地方使用變數。

溫馨小提示:您在學習 sass 時,除了在我們網頁上可以做練習,還有一個便利線上編輯器網址如下:

http://sassmeister.com/

4-5~4-7[Sass]巢狀-選擇器巢狀,屬性巢狀,偽類巢狀

4-8.[Sass]混合巨集-宣告混合巨集

如果你的整個網站中有幾處小樣式類似,比如顏色,字型等,在 Sass 可以使用變數來統一處理,那麼這種選擇還是不錯的。但當你的樣式變得越來越複雜,需要重複使用大段的樣式時,使用變數就無法達到我們目了。這個時候 Sass 中的混合巨集就會變得非常有意義。在這一節中,主要向大家介紹 Sass 的混合巨集。

1、宣告混合巨集

不帶引數混合巨集

在 Sass 中,使用“@mixin”來宣告一個混合巨集。如:

@mixin border-radius{
    -webkit-border-radius: 5px;
    border-radius: 5px;
}

其中 @mixin 是用來宣告混合巨集的關鍵詞,有點類似 CSS 中的 @media、@font-face 一樣。border-radius 是混合巨集的名稱。大括號裡面是複用的樣式程式碼。

帶引數混合巨集

除了宣告一個不帶引數的混合巨集之外,還可以在定義混合巨集時帶有引數,如:

@mixin border-radius($radius:5px){
    -webkit-border-radius: $radius;
    border-radius: $radius;
}

複雜的混合巨集:

上面是一個簡單的定義混合巨集的方法,當然, Sass 中的混合巨集還提供更為複雜的,你可以在大括號裡面寫上帶有邏輯關係,幫助更好的做你想做的事情,如:

@mixin box-shadow($shadow...) {
  @if length($shadow) >= 1 {
    @include prefixer(box-shadow, $shadow);
  } @else{
    $shadow:0 0 4px rgba(0,0,0,.3);
    @include prefixer(box-shadow, $shadow);
  }
}

這個 box-shadow 的混合巨集,帶有多個引數,這個時候可以使用“ … ”來替代。簡單的解釋一下,當 $shadow 的引數數量值大於或等於“ 1 ”時,表示有多個陰影值,反之呼叫預設的引數值“ 0 0 4px rgba(0,0,0,.3) ”。

注:複雜的混合巨集中的邏輯關係(@[email protected])後面小節會有講解。

4-9.[Sass]混合巨集-呼叫混合巨集

在 Sass 中通過 @mixin 關鍵詞聲明瞭一個混合巨集,那麼在實際呼叫中,其匹配了一個關鍵詞“@include”來呼叫宣告好的混合巨集。例如在你的樣式中定義了一個圓角的混合巨集“border-radius”:

@mixin border-radius{
    -webkit-border-radius: 3px;
    border-radius: 3px;
}

在一個按鈕中要呼叫定義好的混合巨集“border-radius”,可以這樣使用:

button {
    @include border-radius;
}

這個時候編譯出來的 CSS:

button {
  -webkit-border-radius: 3px;
  border-radius: 3px;
}

4-10.[Sass]混合巨集的引數--傳一個不帶值的引數

Sass 的混合巨集有一個強大的功能,可以傳參,那麼在 Sass 中傳參主要有以下幾種情形:

A) 傳一個不帶值的引數

在混合巨集中,可以傳一個不帶任何值的引數,比如:

@mixin border-radius($radius){
  -webkit-border-radius: $radius;
  border-radius: $radius;
}

在混合巨集“border-radius”中定義了一個不帶任何值的引數“$radius”。

在呼叫的時候可以給這個混合巨集傳一個引數值:

.box {
  @include border-radius(3px);
}

這裡表示給混合巨集傳遞了一個“border-radius”的值為“3px”。

編譯出來的 CSS:

.box {
  -webkit-border-radius: 3px;
  border-radius: 3px;
}

4-11.[Sass]混合巨集的引數--傳一個帶值的引數

在 Sass 的混合巨集中,還可以給混合巨集的引數傳一個預設值,例如:

@mixin border-radius($radius:3px){
  -webkit-border-radius: $radius;
  border-radius: $radius;
}

在混合巨集“border-radius”傳了一個引數“$radius”,而且給這個引數賦予了一個預設值“3px”。

在呼叫類似這樣的混合巨集時,會多有一個機會,假設你的頁面中的圓角很多地方都是“3px”的圓角,那麼這個時候只需要呼叫預設的混合巨集“border-radius”:

.btn {
  @include border-radius;
}

編譯出來的 CSS:

.btn {
  -webkit-border-radius: 3px;
  border-radius: 3px;
}

但有的時候,頁面中有些元素的圓角值不一樣,那麼可以隨機給混合巨集傳值,如:

.box {
  @include border-radius(50%);
}

編譯出來的 CSS:

.box {
  -webkit-border-radius: 50%;
  border-radius: 50%;
}

4-12.[Sass]混合巨集的引數--傳多個引數

Sass 混合巨集除了能傳一個引數之外,還可以傳多個引數,如:

@mixin center($width,$height){
  width: $width;
  height: $height;
  position: absolute;
  top: 50%;
  left: 50%;
  margin-top: -($height) / 2;
  margin-left: -($width) / 2;
}

在混合巨集“center”就傳了多個引數。在實際呼叫和其呼叫其他混合巨集是一樣的:

.box-center {
  @include center(500px,300px);
}

編譯出來 CSS:

.box-center {
  width: 500px;
  height: 300px;
  position: absolute;
  top: 50%;
  left: 50%;
  margin-top: -150px;
  margin-left: -250px;
}

  有一個特別的引數“”。當混合巨集傳的引數過多之時,可以使用引數來替代,如:

@mixin box-shadow($shadows...){
  @if length($shadows) >= 1 {
    -webkit-box-shadow: $shadows;
    box-shadow: $shadows;
  } @else {
    $shadows: 0 0 2px rgba(#000,.25);
    -webkit-box-shadow: $shadow;
    box-shadow: $shadow;
  }
}

在實際呼叫中:

.box {
  @include box-shadow(0 0 1px rgba(#000,.5),0 0 2px rgba(#000,.2));
}

編譯出來的CSS:

.box {
  -webkit-box-shadow: 0 0 1px rgba(0, 0, 0, 0.5), 0 0 2px rgba(0, 0, 0, 0.2);
  box-shadow: 0 0 1px rgba(0, 0, 0, 0.5), 0 0 2px rgba(0, 0, 0, 0.2);
}

4-13.[Sass]混合巨集的引數--混合巨集的不足

混合巨集在實際編碼中給我們帶來很多方便之處,特別是對於複用重複程式碼塊。但其最大的不足之處是會生成冗餘的程式碼塊。比如在不同的地方呼叫一個相同的混合巨集時。如:

@mixin border-radius{
  -webkit-border-radius: 3px;
  border-radius: 3px;
}

.box {
  @include border-radius;
  margin-bottom: 5px;
}

.btn {
  @include border-radius;
}

示例在“.box”和“.btn”中都呼叫了定義好的“border-radius”混合巨集。先來看編譯出來的 CSS:

.box {
  -webkit-border-radius: 3px;
  border-radius: 3px;
  margin-bottom: 5px;
}

.btn {
  -webkit-border-radius: 3px;
  border-radius: 3px;
}

上例明顯可以看出,Sass 在呼叫相同的混合巨集時,並不能智慧的將相同的樣式程式碼塊合併在一起。這也是 Sass 的混合巨集最不足之處。

4-14.[Sass]擴充套件/繼承

繼承對於瞭解 CSS 的同學來說一點都不陌生,先來看一張圖:

圖中程式碼顯示“.col-sub .block li,.col-extra .block li” 繼承了 “.item-list ul li”選擇器的 “padding : 0;” 和 “ul li” 選擇器中的 “list-style : none outside none;”以及 * 選擇器中的 “box-sizing:inherit;”。

在 Sass 中也具有繼承一說,也是繼承類中的樣式程式碼塊。在 Sass 中是通過關鍵詞 “@extend”來繼承已存在的類樣式塊,從而實現程式碼的繼承。如下所示:

//SCSS
.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;
}

編譯出來之後:

//CSS
.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 {
  border: 1px solid #ccc;
  padding: 6px 10px;
  font-size: 14px;
}

4-15.[Sass]佔位符 %placeholder

Sass 中的佔位符 %placeholder 功能是一個很強大,很實用的一個功能,這也是我非常喜歡的功能。他可以取代以前 CSS 中的基類造成的程式碼冗餘的情形。因為 %placeholder 宣告的程式碼,如果不被 @extend 呼叫的話,不會產生任何程式碼。來看一個演示:

%mt5 {
  margin-top: 5px;
}
%pt5{
  padding-top: 5px;
}

這段程式碼沒有被 @extend 呼叫,他並沒有產生任何程式碼塊,只是靜靜的躺在你的某個 SCSS 檔案中。只有通過 @extend 呼叫才會產生程式碼:

//SCSS
%mt5 {
  margin-top: 5px;
}
%pt5{
  padding-top: 5px;
}

.btn {
  @extend %mt5;
  @extend %pt5;
}

.block {
  @extend %mt5;

  span {
    @extend %pt5;
  }
}

編譯出來的CSS

//CSS
.btn, .block {
  margin-top: 5px;
}

.btn, .block span {
  padding-top: 5px;
}

從編譯出來的 CSS 程式碼可以看出,通過 @extend 呼叫的佔位符,編譯出來的程式碼會將相同的程式碼合併在一起。這也是我們希望看到的效果,也讓你的程式碼變得更為乾淨。

4-16.[Sass]混合巨集 VS 繼承 VS 佔位符

初學者都常常糾結於這個問題“什麼時候用混合巨集,什麼時候用繼承,什麼時候使用佔位符?”其實他們各有各的優點與缺點,先來看看他們使用效果:

a) Sass 中的混合巨集使用

舉例程式碼見右側 2-24 行

編譯出來的 CSS 見右側結果視窗。

總結:編譯出來的 CSS 清晰告訴了大家,他不會自動合併相同的樣式程式碼,如果在樣式檔案中呼叫同一個混合巨集,會產生多個對應的樣式程式碼,造成程式碼的冗餘,這也是 CSSer 無法忍受的一件事情。不過他並不是一無事處,他可以傳引數。

個人建議:如果你的程式碼塊中涉及到變數,建議使用混合巨集來建立相同的程式碼塊。

b) Sass 中繼承

同樣的,將上面程式碼中的混合巨集,使用類名來表示,然後通過繼承來呼叫:

程式碼見右側 26-48 行

總結:使用繼承後,編譯出來的 CSS 會將使用繼承的程式碼塊合併到一起,通過組合選擇器的方式向大家展現,比如 .mt, .block, .block span, .header, .header span。這樣編譯出來的程式碼相對於混合巨集來說要乾淨的多,也是 CSSer 期望看到。但是他不能傳變數引數。

個人建議:如果你的程式碼塊不需要專任何變數引數,而且有一個基類已在檔案中存在,那麼建議使用 Sass 的繼承。

c) 佔位符

最後來看佔位符,將上面程式碼中的基類 .mt 換成 Sass 的佔位符格式:

程式碼見右側 50-72 行

總結:編譯出來的 CSS 程式碼和使用繼承基本上是相同,只是不會在程式碼中生成佔位符 mt 的選擇器。那麼佔位符和繼承的主要區別的,“佔位符是獨立定義,不呼叫的時候是不會在 CSS 中產生任何程式碼;繼承是首先有一個基類存在,不管呼叫與不呼叫,基類的樣式都將會出現在編譯出來的 CSS 程式碼中。”

來看一個表格:

4-17.[Sass]插值#{}

使用 CSS 前處理器語言的一個主要原因是想使用 Sass 獲得一個更好的結構體系。比如說你想寫更乾淨的、高效的和麵向物件的 CSS。Sass 中的插值(Interpolation)就是重要的一部分。讓我們看一下下面的例子:

$properties: (margin, padding);
@mixin set-value($side, $value) {
    @each $prop in $properties {
        #{$prop}-#{$side}: $value;
    }
}
.login-box {
    @include set-value(top, 14px);
}

@each...in...語句會在《Sass進級篇》中 1-6 @each迴圈 中講解。

它可以讓變數和屬性工作的很完美,上面的程式碼編譯成 CSS:

.login-box {
    margin-top: 14px;
    padding-top: 14px;
}

這是 Sass 插值中一個簡單的例項。當你想設定屬性值的時候你可以使用字串插入進來。另一個有用的用法是構建一個選擇器。可以這樣使用:

@mixin generate-sizes($class, $small, $medium, $big) {
    .#{$class}-small { font-size: $small; }
    .#{$class}-medium { font-size: $medium; }
    .#{$class}-big { font-size: $big; }
}
@include generate-sizes("header-text", 12px, 20px, 40px);

編譯出來的 CSS:

.header-text-small { font-size: 12px; }
.header-text-medium { font-size: 20px; }
.header-text-big { font-size: 40px; }

一旦你發現這一點,你就會想到超級酷的 mixins,用來生成程式碼或者生成另一個 mixins。然而,這並不完全是可能的。第一個限制,這可能會很刪除用於 Sass 變數的插值。

$margin-big: 40px;
$margin-medium: 20px;
$margin-small: 12px;
@mixin set-value($size) {
    margin-top: $margin-#{$size};
}
.login-box {
    @include set-value(big);
}

上面的 Sass 程式碼編譯出來,你會得到下面的資訊:

error style.scss (Line 5: Undefined variable: “$margin-".)

所以,#{}語法並不是隨處可用,你也不能在 mixin 中呼叫:

@mixin updated-status {
    margin-top: 20px;
    background: #F00;
}
$flag: "status";
.navigation {
    @include updated-#{$flag};
}

上面的程式碼在編譯成 CSS 時同樣會報錯:

error style.scss (Line 7: Invalid CSS after "...nclude updated-": expected "}", was "#{$flag};")
幸運的是,可以使用 @extend 中使用插值。例如:

%updated-status {
    margin-top: 20px;
    background: #F00;
}
.selected-status {
    font-weight: bold;
}
$flag: "status";
.navigation {
    @extend %updated-#{$flag};
    @extend .selected-#{$flag};
}


上面的 Sass 程式碼是可以執行的,因為他給了我們力量,可以動態的插入 .class 和 %placeholder。當然他們不能接受像 mixin 這樣的引數,上面的程式碼編譯出來的 CSS:

.navigation {
    margin-top: 20px;
    background: #F00;
}
.selected-status, .navigation {
    font-weight: bold;
}


在 Sass 的社群正在積極討論插值的侷限性,誰又知道呢,也許我們很快將能夠使用這些技術也說不定呢。

4-18.[Sass]註釋

1、類似 CSS 的註釋方式,使用 ”/* ”開頭,結屬使用 ”*/ ”
2、類似 JavaScript 的註釋方式,使用“//”

兩者區別,前者會在編譯出來的 CSS 顯示,後者在編譯出來的 CSS 中不會顯示,來看一個示例:

//定義一個佔位符

%mt5 {
  margin-top: 5px;
}

/*呼叫一個佔位符*/

.box {
  @extend %mt5;
}

編譯出來的CSS

.box {
  margin-top: 5px;
}

/*呼叫一個佔位符*/

4-19.[Sass]資料型別

 Sass 和 JavaScript 語言類似,也具有自己的資料型別,在 Sass 中包含以下幾種資料型別:

  •  數字: 如,1、 2、 13、 10px;
  •  字串:有引號字串或無引號字串,如,"foo"、 'bar'、 baz;
  •  顏色:如,blue、 #04a3f9、 rgba(255,0,0,0.5);
  •  布林型:如,true、 false;
  •  空值:如,null;
  •  值列表:用空格或者逗號分開,如,1.5em 1em 0 2em 、 Helvetica, Arial, sans-serif。


SassScript 也支援其他 CSS 屬性值(property value),比如 Unicode 範圍,或 !important 宣告。然而,Sass 不會特殊對待這些屬性值,一律視為無引號字串 (unquoted strings)。

後兩個小節詳細講解字串和值列表資料型別,其它型別與JavaScript中的用法一致。

4-20.[Sass]字串

SassScript 支援 CSS 的兩種字串型別:

  • 有引號字串 (quoted strings),如 "Lucida Grande"、'http://sass-lang.com';
  • 無引號字串 (unquoted strings),如 sans-serifbold。

在編譯 CSS 檔案時不會改變其型別。只有一種情況例外,使用 #{ }插值語句 (interpolation) 時,有引號字串將被編譯為無引號字串,這樣方便了在混合指令 (mixin) 中引用選擇器名。

@mixin firefox-message($selector) {
  body.firefox #{$selector}:before {
    content: "Hi, Firefox users!";
  }
}
@include firefox-message(".header");

編譯為:

body.firefox .header:before {
  content: "Hi, Firefox users!"; }

需要注意的是:當 deprecated = property syntax 時 (暫時不理解是怎樣的情況),所有的字串都將被編譯為無引號字串,不論是否使用了引號。

4-21.[Sass]值列表

所謂值列表 (lists) 是指 Sass 如何處理 CSS 中: 

margin: 10px 15px 0 0

或者: 

font-face: Helvetica, Arial, sans-serif

像上面這樣通過空格或者逗號分隔的一系列的值。

事實上,獨立的值也被視為值列表——只包含一個值的值列表。

Sass列表函式(Sass list functions)賦予了值列表更多功能(Sass進級會有講解):

  1. nth函式(nth function) 可以直接訪問值列表中的某一項;
  2. join函式(join function) 可以將多個值列表連結在一起;
  3. append函式(append function) 可以在值列表中新增值; 
  4. @each規則(@each rule) 則能夠給值列表中的每個專案新增樣式。

值列表中可以再包含值列表,比如 1px 2px, 5px 6px 是包含 1px 2px 與 5px 6px 兩個值列表的值列表。如果內外兩層值列表使用相同的分隔方式,要用圓括號包裹內層,所以也可以寫成 (1px 2px) (5px 6px)。當值列表被編譯為 CSS 時,Sass 不會新增任何圓括號,因為 CSS 不允許這樣做。(1px 2px) (5px 6px)與 1px 2px 5px 6px 在編譯後的 CSS 檔案中是一樣的,但是它們在 Sass 檔案中卻有不同的意義,前者是包含兩個值列表的值列表,而後者是包含四個值的值列表。

可以用 () 表示空的列表,這樣不可以直接編譯成 CSS,比如編譯 font-family: ()時,Sass 將會報錯。如果值列表中包含空的值列表或空值,編譯時將清除空值,比如 1px 2px () 3px 或 1px 2px null 3px。

第五章 【sass的運算】

5-1.[Sass運算]加法

程式中的運算是常見的一件事情,但在 CSS 中能做運算的,到目前為止僅有 calc() 函式可行。但在 Sass 中,運算只是其基本特性之一。在 Sass 中可以做各種數學計算,在接下來的章節中,主要和大家一起探討有關於 Sass 中的數學運算。

(一)、加法

加法運算是 Sass 中運算中的一種,在變數或屬性中都可以做加法運算。如:

.box {
  width: 20px + 8in;
}

編譯出來的 CSS:

.box {
  width: 788px;
}

但對於攜帶不同型別的單位時,在 Sass 中計算會報錯,如下例所示:

.box {
  width: 20px + 1em;
}

編譯的時候,編譯器會報錯:“Incompatible units: 'em' and ‘px'.”

5-2.[Sass運算]減法

Sass 的減法運算和加法運算類似,

$full-width: 960px;
$sidebar-width: 200px;

.content {
  width: $full-width -  $sidebar-width;
}

編譯出來的 CSS 如下:

.content {
  width: 760px;
}

同樣的,運算時碰到不同型別的單位時,編譯也會報錯,如:

$full-width: 960px;

.content {
  width: $full-width -  1em;
}

編譯的時候,編譯器報“Incompatible units: 'em' and ‘px’.”錯誤。

5-3.[Sass運算]乘法

Sass 中的乘法運算和前面介紹的加法與減法運算還略有不同。雖然他也能夠支援多種單位(比如 em ,px , %),但當一個單位同時宣告兩個值時會有問題。比如下面的示例:

.box {
  width:10px * 2px;  
}

編譯的時候報“20px*px isn't a valid CSS value.”錯誤資訊。

如果進行乘法運算時,兩個值單位相同時,只需要為一個數值提供單位即可。上面的示例可以修改成:

.box {
  width: 10px * 2;
}

編譯出來的 CSS:

.box {
  width: 20px;
}

Sass 的乘法運算和加法、減法運算一樣,在運算中有不同型別的單位時,也將會報錯。如下面的示例:

.box {
  width: 20px * 2em;
}

編譯時報“40em*px isn't a valid CSS value.”錯誤資訊。

5-4.[Sass運算]除法

”/  ”符號被當作除法運算子時有以下幾種情況:

•    如果數值或它的任意部分是儲存在一個變數中或是函式的返回值。
•    如果數值被圓括號包圍。
•    如果數值是另一個數學表示式的一部分。

如下所示:

//SCSS
p {
  font: 10px/8px;             // 純 CSS,不是除法運算
  $width: 1000px;
  width: $width/2;            // 使用了變數,是除法運算
  width: round(1.5)/2;        // 使用了函式,是除法運算
  height: (500px/2);          // 使用了圓括號,是除法運算
  margin-left: 5px + 8px/2px; // 使用了加(+)號,是除法運算
}

編譯出來的CSS

p {
  font: 10px/8px;
  width: 500px;
  height: 250px;
  margin-left: 9px;
 }

注意:(1)在乘除時,不同單位為會報錯。(2)兩個數值做運算只需帶一個單位即可。
Sass 的除法運算還有一個情況。我們先回憶一下,在乘法運算時,如果兩個值帶有相同單位時,做乘法運算時,出來的結果並不是我們需要的結果。但在除法運算時,如果兩個值帶有相同的單位值時,除法運算之後會得到一個不帶單位的數值。如下所示:

.box {
  width: (1000px / 100px);
}

編譯出來的CSS如下:

.box {
  width: 10;
}

5-5.[Sass運算]變數計算

在 Sass 中除了可以使用數值進行運算之外,還可以使用變數進行計算,其實在前面章節的示例中也或多或少的向大家展示了。在 Sass 中使用變數進行計算,這使得 Sass 的數學運算功能變得更加實用。一起來看一個簡單的示例:

$content-width: 720px;
$sidebar-width: 220px;
$gutter: 20px;

.container {
  width: $content-width + $sidebar-width + $gutter;
  margin: 0 auto;
}

編譯出來的CSS

.container {
  width: 960px;
  margin: 0 auto;
}

5-6.[Sass運算]數字運算

在 Sass 運算中數字運算是較為常見的,數字運算包括前面介紹的:加法、減法、乘法和除法等運算。而且還可以通過括號來修改他們的運算先後順序。和我們數學運算是一樣的,一起來看個示例。

.box {
  width: ((220px + 720px) - 11 * 20 ) / 12 ;  
}

編譯出來的 CSS:

.box {
  width: 60px;
}

上面這個簡單示例是一個典型的計算 Grid 單列列寬的運算。

5-7.[Sass運算]顏色運算

所有算數運算都支援顏色值,並且是分段運算的。也就是說,紅、綠和藍各顏色分段單獨進行運算。如:

p {
  color: #010203 + #040506;
}

計算公式為 01 + 04 = 05、02 + 05 = 07 和 03 + 06 = 09, 並且被合成為:

如此編譯出來的 CSS 為:

p {
  color: #050709;
}

算數運算也能將數字和顏色值 一起運算,同樣也是分段運算的。如:

p {
  color: #010203 * 2;
}

計算公式為 01 * 2 = 02、02 * 2 = 04 和 03 * 2 = 06, 並且被合成為:

p {
  color: #020406;
}

5-8.[Sass運算]字元運算

在 Sass 中可以通過加法符號“+”來對字串進行連線。例如:

$content: "Hello" + "" + "Sass!";
.box:before {
  content: " #{$content} ";
}

編譯出來的CSS:

.box:before {
  content: " Hello Sass! ";
}

除了在變數中做字元連線運算之外,還可以直接通過 +,把字元連線在一起:

div {
  cursor: e + -resize;
}

編譯出來的CSS:

div {
  cursor: e-resize;
}

注意,如果有引號的字串被添加了一個沒有引號的字串 (也就是,帶引號的字串在 + 符號左側), 結果會是一個有引號的字串。 同樣的,如果一個沒有引號的字串被添加了一個有引號的字串 (沒有引號的字串在 + 符號左側), 結果將是一個沒有引號的字串。 例如:

p:before {
  content: "Foo " + Bar;
  font-family: sans- + "serif";
}

編譯出來的 CSS:

p:before {
  content: "Foo Bar";
  font-family: sans-serif; }