element 源碼學習(番外篇) —— SASS五分鐘快速入門

這算是 element 源碼學習的番外篇,由於 element 中使用了大量 sass 來寫樣式。而 UI 框架的核心其實就是樣式。因此,抽空把 sass 學了一遍,寫了些小 demo 實踐,總結成此文。

SASS 安裝和調試

簡單說下 sass 如何安裝和編譯調試。
參照官網,須要使用 gem 來安裝 sass。若是是windows用戶沒有 gem 須要先安裝 Rubycss

$ gem install sass

若是有權限問題,須要加上 sudohtml

$ sudo gem install sass

最後,經過查詢 sass 版本號驗證是否安裝成功。web

$ sass -v

編譯命令很簡單,在項目目錄下編譯選中 .scss.sass 文件便可。shell

$ sass hello.scss hello.css

若是是學習 sass 這一個命令足矣,其餘命令可參考sass 編譯編程

語法簡述

下面我用本身對 sass 語法的理解,配合上 demo 快速過一遍 sass 基礎語法。windows

sass 文件和 scss 文件區別

二者其實都是 sass 能夠識別的文件,惟一不一樣點是 .sass 文件不使用大括號和分號。以下~瀏覽器

// .scss
$default-color: #FFAACC;
.selected {
    color: $default-color;
}

// .sass
$default-color: #FFAACC
.selected 
    color: $default-color

// .css
.selected {
  color: #FFAACC; 
}

官方文檔推薦使用 .scss 文件類型寫法,避免 .sass 文件的嚴格格式要求報錯。sass

變量

經過 $ 符號來定義 sass 變量,變量在樣式內外均可定義,用於各個樣式中。定義的變量不會在編譯後的 CSS 文件中顯示。ruby

$default-color: #FFAACC;
$border-color: #AAFFCC;
$default-border:  1px solid $border-color;
$extra-color: #BBDD00;

.selected {
    $scoped-width: 60px;
    width: $scoped-width;
    color: $default-color;
    border: $default-border;
}

編譯結果:框架

.selected {
  width: 60px;
  color: #FFAACC;
  border: 1px solid #AAFFCC; }

另外注意的一個點是在定義變量時使用的 -_ 的效果是同樣的。即 $border-color$border_color 指向的是同一個變量。

嵌套

爲了不一些代碼的重複,引入了代碼的嵌套。看一個例子:

.selected {
    color: #FFAA22;
    h1 {
        color: #FFDD77
    }
    div {
        width: 50px;
        height: 20px;
        span {
            color: #012DD6;
        }
    }
    &:hover {
        color: #FAFAFA;
    }
}

獲得的結果以下:

.selected {
  color: #FFAA22; }
  .selected h1 {
    color: #FFDD77; }
  .selected div {
    width: 50px;
    height: 20px; }
    .selected div span {
      color: #012DD6; }
  .selected:hover {
    color: #FAFAFA; }

從中能夠看到,嵌套能夠將須要重複寫選擇器的過程嵌套到一個表達式中了。

父選擇器標識符 &

從上面的例子中看到有這麼一段 &:hover 而在編譯結果中獲得的結果是 .selected:hover ,其實 & 標識符就表明了父級選擇器。就這麼簡單,不理解的時候把父級選擇題替換 & 理解下就簡單了。

嵌套css

sass 中的嵌套是能夠多個樣式同時嵌套的。 用法見demo。

.container .content {
    h1, h2, h3 {margin-bottom: .8em}
}

編譯結果

.container .content h1, .container .content h2, .container .content h3 {
  margin-bottom: .8em; }

子組合選擇器和同層選擇器

關於 >+~ 這三個選擇器,是 CSS3 中就有的。在 SASS 中一樣適用。
簡單說下三個選擇器用途(參考 CSS 選擇器):

  • div>p 選取父元素是 <div> 元素的每一個 <p> 元素
  • div+p 選擇 <div> 元素以後緊跟的每一個 <p> 元素
  • p~ul 選擇前面有 <p> 元素的每一個 <ul> 元素。

看個官網的例子:

article {
    ~ article { border-top: 1px dashed #ccc }
    > section { background: #eee }
    dl > {
      dt { color: #333 }
      dd { color: #555 }
    }
    nav + & { margin-top: 0 }
}

動手編譯出的結果以下:

article ~ article {
  border-top: 1px dashed #ccc; }
article > section {
  background: #eee; }
article dl > dt {
  color: #333; }
article dl > dd {
  color: #555; }
nav + article {
  margin-top: 0; }

嵌套屬性

屬性嵌套說白了就是把 margin-bottom 這類有 - 符號隔開的屬性拆分開來便於查看和編寫。

nav {
    border: {
    style: solid;
    width: 1px;
    color: #ccc;
    }
  }

這裏把 border-style 等屬性進行了拆分,結果以下:

nav {
  border-style: solid;
  border-width: 1px;
  border-color: #ccc; }

導入

sass 提供了 sass 文件導入功能。能夠作一些基礎樣式的複用。用法很簡單:

// var.scss
$default-color: #AABBCC;

.focused {
    color: red;
    margin: 5px;
}

// h1.scss
h1 {
    color: #BBDDFF;
    margin: 10px;
}

// demo.scss
@import "var01";

$default-color: #FFAADD !default;

.selected {
    color: $default-color;
    @import "h1";
}

以上代碼中將 var.scssh1.scss 兩個文件導入到了 demo.scss 中,最終生成結果以下:

.focused {
  color: red;
  margin: 5px; }

.selected {
  color: #AABBCC; }
  .selected h1 {
    color: #BBDDFF;
    margin: 10px; }

從結果來講說導入的幾個注意點:

  • 導入文件使用 @import 表達式來導入,導入能夠是外部導入也但是嵌套導入。上面例子中 var 是外部導入,而 h1 是嵌套導入的。
  • $default-color: #FFAADD !default; 中的 !default 是定義變量默認值的方式,若是導入文件中有一樣的值優先使用導入的值,若是導入文件中沒有這個值,使用默認值。
  • sass 中的 @import 與 css 中的 @import 不一樣,sass 中是編譯的時候就直接導入生成 css 文件了,而 css 中,只有執行到 @import 時,瀏覽器纔會去下載 css 文件,會致使頁面加載變慢。

靜默註釋

就是在 sass 是否保留註釋內容的語法。保留註釋的方式爲:在CSS語法容許的地方,以 /*...*/ 的方式寫註釋就能在生成的 css 文件中看到。再來看一個例子:

// 不顯示
/* 顯示 */

.selected {
    //不顯示
    /* 顯示 */
    color: #FFAADD; // 不顯示
    margin:/* 不顯示 */ 10px; /* 顯示 */
    /* 顯示 */border: 1px dashed /* 不顯示 */ #ccc;
}

// 不顯示
/* 顯示 */

編譯結果正如註釋所預測的。

混合器

混合器在 element 的樣式表中用的很是多,是個很強大的功能。混合器以 @mixin 來導出混合內容,使用 @include 來導入混合內容。

基本用法

個人理解是:@mixin 相似定義變量同樣定義個混合器(編譯的時候不顯示 @mixin 的內容),@include 獲取混合器來替換 @include xxxx 的這行內容。

// mixin.scss
@mixin rounded-corners {
    -moz-border-radius: 5px;
    -webkit-border-radius: 5px;
    border-radius: 5px;
    div {
        width: 50px;
        height: 20px;
    }
}

.name {
    span {
        color: #FFAADD;
    }
}

// include.scss
@import "mixin";

.notice {
    background-color: green;
    border: 2px solid #00aa00;
    @include rounded-corners;
}

這裏在官方 demo 上加了點代碼驗證問題。獲得結果以下:

.name span {
  color: #FFAADD; }

.notice {
  background-color: green;
  border: 2px solid #00aa00;
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
  border-radius: 5px; }
  .notice div {
    width: 50px;
    height: 20px; }

這個demo驗證了:1. @mixin 是一個相似變量的內容。在 @import 導入的內容中只顯示了 .name 樣式。 2. @include 會替換 @include xxx 這段代碼。就算 @mixin 中有各類寫法都會應用到 @include中,如嵌套 CSS。

混合器傳參

混合器能夠接收 @include 表達式傳遞的參數。並且,參數能夠設置默認值。

// mixin.scss
@mixin link-colors($normal: white, $hover: white, $visited: white) {
    color: $normal;
    &:hover { color: $hover; }
    &:visited { color: $visited; }
}

// include.scss
@import "mixin";

// 寫法一,按照默認順序傳遞參數
a {
    @include link-colors(blue, red, green);
}

// 寫法二,按照參數名傳遞參數
b {
    @include link-colors(
      $normal: blue,
      $visited: green,
      $hover: red
  );
}

編譯結果爲:

a {
  color: blue; }
  a:hover {
    color: red; }
  a:visited {
    color: green; }

b {
  color: blue; }
  b:hover {
    color: red; }
  b:visited {
    color: green; }

若是說 @include 中不傳遞參數 @include link-colors(); ,那麼生成結果的 color 都爲默認值 white。

element 中的混合

在 element 源碼中用了很多混合,有一種寫法 sass 的快速入門中沒有提到。就找一個簡單的 el-card 樣式來學習下來:

@import "mixins/mixins";
@import "common/var";

@include b(card) {
  border-radius: $--card-border-radius;
  border: 1px solid $--card-border-color;
  background-color: $--color-white;
  overflow: hidden;
  box-shadow: $--box-shadow-light;
  color: $--color-text-primary;

  @include e(header) {
    padding: #{$--card-padding - 2 $--card-padding};
    border-bottom: 1px solid $--card-border-color;
    box-sizing: border-box;
  }

  @include e(body) {
    padding: $--card-padding;
  }
}

從中能夠看到全部的屬性都是使用了 @include 方式進行混合的。最終生成的 CSS 文件以下:

.el-card {
  border-radius: 4px;
  border: 1px solid #ebeef5;
  background-color: #fff;
  overflow: hidden;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  color: #303133; }
  .el-card__header {
    padding: 18px 20px;
    border-bottom: 1px solid #ebeef5;
    box-sizing: border-box; }
  .el-card__body {
    padding: 20px; }

先看下導入,其中 var 文件是項目樣式變量統一保存的地方;mixin 文件用於混合;再加上幾個 @include 表達式,答案必定是在 mixin 中的。咱們就直接找到 @mixin b@mixin e 兩個混合項。

@mixin b($block) {
  $B: $namespace+'-'+$block !global; // 定義 B 變量:變量名 el-card

  .#{$B} {
    @content;
  }
}

@mixin e($element) {
  $E: $element !global;
  $selector: &;
  $currentSelector: "";
  @each $unit in $element {
    $currentSelector: #{$currentSelector + "." + $B + $element-separator + $unit + ","};
  }

  @if hitAllSpecialNestRule($selector) {
    @at-root {
      #{$selector} {
        #{$currentSelector} {
          @content;
        }
      }
    }
  } @else {
    @at-root {
      #{$currentSelector} {
        @content;
      }
    }
  }
}

發現有許多 sass 快速入門中沒有提到過的語法: @if@else 等等,這裏查閱具體文檔列出其功能:

  • @if @else 這二者和任何編程語言的 if ... else ... 的用法是同樣的,條件判斷。if 中條件爲 true 進入邏輯,不然使用 else 邏輯。
  • @at-root @at-root 指令致使一個或多個規則被限定輸出在文檔的根層級上,而不是被嵌套在其父選擇器下。
  • @content 樣式內容塊能夠傳遞到混入(mixin)包含樣式的位置。樣式內容塊將出如今混入內的任何 @content 指令的位置。這使得能夠定義抽象 關聯到選擇器和指令的解析。
  • @each in 相似js用法,遍歷列表獲取每一個value值。
  • #{...}插值語法,用於在選擇器和屬性名中使用 SassScript 變量,因此 .#{$B} 表達式,若是 $B 的值爲 hello-world,那麼表達式結果等於 .hello-world

其實看完這些用法,上面的代碼就很好理解了。具體關於 element 樣式學習的細節將在下篇博客中詳細學習。

繼承

我的感受繼承就是幾個樣式類寫在一塊兒。並且,繼承是能夠嵌套的。

.error {
    border: 1px red;
    background-color: #fdd;
}
  
.seriousError {
    @extend .error;
    border-width: 3px;
}

.error02 {
    @extend .seriousError;
    margin: 5px;
}

編譯結果爲:

.error, .seriousError, .error02 {
  border: 1px red;
  background-color: #fdd; }

.seriousError, .error02 {
  border-width: 3px; }

.error02 {
  margin: 5px; }

下面引用下繼承的注意事項:

  • 跟混合器相比,繼承生成的 css 代碼相對更少。由於繼承僅僅是重複選擇器,而不會重複屬性,因此使用繼承每每比混合器生成的 css 體積更小。若是你很是關心你站點的速度,請牢記這一點。
  • 繼承聽從 css 層疊的規則。當兩個不一樣的 css 規則應用到同一個 html 元素上時,而且這兩個不一樣的 css 規則對同一屬性的修飾存在不一樣的值,css 層疊規則會決定應用哪一個樣式。至關直觀:一般權重更高的選擇器勝出,若是權重相同,定義在後邊的規則勝出。

因此,其實繼承相比混合更簡單。繼承只是選擇器的重複,而混合是用一段代碼替換標籤 @include 標籤。

最後

因爲 element 項目中使用了大量的 sass 樣式,因此想了解 element 必須對 sass 有必定了解。本文簡單解決了 sass 是什麼?基礎用法怎麼用?兩個問題。更加深刻的 sass 語法涉及的很少,算是快速入門博客啦。在瞭解了 sass,可以看懂 element 中的樣式表後,就能夠愉快的去學習 element 源碼啦~

相關文章
相關標籤/搜索