SASS入門與實踐

艾倫先生發表於2017-12-14

前言

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;
      }
    複製程式碼

可見,SassCSS的書寫語法差別很大,而Sass書寫則和CSS幾乎一樣,所以這也是為什麼越來越多的前端開發使用Sass中的SCSS方式來開發的原因

Sass的安裝

MAC系統

  • brew install ruby
  • sudo gem install sass
  • sass -v

Window系統

SASS入門與實踐

開啟ruby 命令列

命令列輸入  gem install sass
複製程式碼

如果上面安裝失敗,可能是因為該安裝途徑已經被牆了,需要更換安裝的源,這裡我們使用淘寶的源,附上安裝步驟

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; }
複製程式碼

相關文章